Found incidentally while building #8119's dogfood control — it is what made a "grant a share on a local record" control fail with 404. Filed unassigned. Scope caveat up front: I have not established whether this reproduces on a real deployment (see "What I did not check"), which is exactly why this is a finding rather than a bug report.
Measured, on a booted showcase stack
Boot: bootStack(showcaseStack, { multiTenant: 'posture-only' }). The boot log reports the wall is on:
INFO [security] tenancy posture 'isolated' — the Layer 0 organization wall is ACTIVE
(organization_id = active organization)
The seeded platform admin (stack.signIn()) resolves an authz context carrying no tenantId at all — its keys are positions, permissions, systemPermissions, org_user_ids, accessible_org_ids, accessToken, email, userId, posture.
That admin then creates a private record through the real HTTP path and reads it back:
POST /api/v1/data/showcase_private_note -> 2xx, row created
stored row: { owner_id: 'PK07N5…', created_by: 'PK07N5…', ← the admin, both
organization_id: null, owning_business_unit_id: null }
GET /api/v1/data/showcase_private_note -> 200 {"records":[],"total":0}
GET /api/v1/data/showcase_private_note/:id -> 404
The row exists (a system-context find returns it in full). Its creator owns it. And its creator cannot see it through either read surface.
Why it happens, as far as I traced it
The write stamps organization_id from the caller's active organization, which is absent, so the row is born org-less. The read then applies the Layer 0 wall, and "no active organization" is deliberately not "every organization" — the fail-closed rule stated in activeOrganizationId's docblock and ADR-0095 D1 / ADR-0105 D1. Both halves are individually correct and defensible. Together they produce a write that succeeds and a record that is unreachable by the person who just made it.
The asymmetry is the interesting part: the write path treats a missing active org as "stamp NULL and proceed", while the read path treats the same missing value as "deny". If the write is allowed to proceed without an organization, something has to be able to read the result back.
What I did not check
- Whether a real (non-harness) deployment ever puts an admin in this state. A seeded admin with no default organization membership may be specific to the verify harness's boot, in which case this is a test-fixture sharpness issue and not a product defect. Checking that is the first triage step.
- Whether the same happens under
single / group postures, or only isolated. - Whether the write path should refuse, stamp a default, or the read path should admit org-less rows to their owner — three different fixes with different blast radii, which is why this carries no recommendation.
Related
Generated by Claude Code
Found incidentally while building #8119's dogfood control — it is what made a "grant a share on a local record" control fail with 404. Filed unassigned. Scope caveat up front: I have not established whether this reproduces on a real deployment (see "What I did not check"), which is exactly why this is a finding rather than a bug report.
Measured, on a booted showcase stack
Boot:
bootStack(showcaseStack, { multiTenant: 'posture-only' }). The boot log reports the wall is on:The seeded platform admin (
stack.signIn()) resolves an authz context carrying notenantIdat all — its keys arepositions, permissions, systemPermissions, org_user_ids, accessible_org_ids, accessToken, email, userId, posture.That admin then creates a private record through the real HTTP path and reads it back:
The row exists (a system-context
findreturns it in full). Its creator owns it. And its creator cannot see it through either read surface.Why it happens, as far as I traced it
The write stamps
organization_idfrom the caller's active organization, which is absent, so the row is born org-less. The read then applies the Layer 0 wall, and "no active organization" is deliberately not "every organization" — the fail-closed rule stated inactiveOrganizationId's docblock and ADR-0095 D1 / ADR-0105 D1. Both halves are individually correct and defensible. Together they produce a write that succeeds and a record that is unreachable by the person who just made it.The asymmetry is the interesting part: the write path treats a missing active org as "stamp NULL and proceed", while the read path treats the same missing value as "deny". If the write is allowed to proceed without an organization, something has to be able to read the result back.
What I did not check
single/grouppostures, or onlyisolated.Related
create_recordunderrunAs:'system'inserts rows withowner_id/organization_id/created_byall NULL — records born untouchable even by admin #5494 (closed) — the adjacent shape from the other direction: automationcreate_recordunderrunAs:'system'inserting rows withowner_id/organization_id/created_byall NULL, "records born untouchable even by admin". Hereowner_idandcreated_byARE set correctly and only the org is null, so it is not the same defect, but it is the same failure family.manage_sharingholder whose session has no ACTIVE organization reads every tenant's sharing rules (adminOrgScope falls open) #8158 — the other open card about a session with no active organization, from the opposite failure direction (falling open rather than closed).Generated by Claude Code