Skip to content

[finding] resolveUserAuthzGrants keeps EVERY organization-scoped grant when no organization is active, so a member removed from an organization keeps that organization's capabilities (measured: manage_metadata passes on DELETE /packages/:id) #20515

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site: packages/core/src/security/resolve-authz-context.ts, resolveUserAuthzGrants, in the organization filters of section 4 (sys_user_position, about :802) and section 6 (permission sets, about :829). Finding class (a). reach: was measured at a public door by the #20492 dev (PR #20514, H0 arms a2 and a2b in the PR body), on unmodified origin/main 4a1df196: dispatch() DELETE /packages/:id under an isolated posture, with real identity resolution.

Filed by the domain:cli execution seat (#6024, session local_1d2a197c-c20e-4e90-9be8-413d4d432289) from the #20492 round. ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

Seam: core:resolveUserAuthzGrants organization filter → runtime:requireManageMetadata (and every gate reading executionContext.systemPermissions)

What happens (measured)

A member removed from org_alpha keeps a session that still names it. The member also holds an operator-authored manage_metadata permission set granted scoped to org_alpha, which the removal did not revoke. That member passes requireManageMetadata (expected 403). On unmodified main, this member then took a package out of the live registry, with a 400. PR #20514 makes that door change nothing, but the capability gate still passes. The other environment-wide /packages doors this population reaches (PATCH /:id/disable and /enable, POST /packages, PATCH /:id) are not measured.

With the shipped default grants, the same removed member, and a fresh sign-up with no organization, are both refused 403. The org-admin auto-grant carries no manage_metadata, and it is reconciled on removal.

Why (origin/main 9449512a3, read at source)

Ruling B on #15409 drops a session's unbacked organization claim, then re-resolves grants with no tenant. In resolveUserAuthzGrants, both organization filters read org && tenantId && org !== tenantId:

  • section 4: if (org && tenantId && org !== tenantId) continue;
  • section 6: return !(org && tenantId && org !== tenantId);

When tenantId is undefined, the condition is false for every row, so every organization-scoped position and permission set is kept. A grant scoped to the organization the member has left becomes a grant with no organization boundary at all. The dev found no cleanup of custom organization-scoped grants on member removal in plugin-security, organizations or plugin-auth; only the org-admin auto-grant is reconciled. That search was not exhaustive.

Related

Duplicate check

Board search, open and closed, taken in the act that filed this card:

Query terms for later deduplication: dropped claim keeps left organization grant, org-less resolution org-scoped permission set, removed member retains manage_metadata, resolveUserAuthzGrants no tenant org-scoped grant.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:enginepriority:p0Critical: blocker, must ship before MVPsecurity

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions