Skip to content

fix(organization): scope ORGANIZATION_MEMBER_UPDATE_ROLE to the authenticated org - #7000

Merged
pedrofrxncx merged 1 commit into
mainfrom
fix/member-update-role-org-scope-guard-w4
Sep 4, 2026
Merged

fix(organization): scope ORGANIZATION_MEMBER_UPDATE_ROLE to the authenticated org#7000
pedrofrxncx merged 1 commit into
mainfrom
fix/member-update-role-org-scope-guard-w4

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Follows the org-scoping lane (#3388, and the same class already fixed in update.ts/member-add.ts/member-remove.ts/delete.ts).

ORGANIZATION_MEMBER_UPDATE_ROLE accepts an optional organizationId input, but unlike its siblings it never checked that value against ctx.organization?.id (the path-resolved org ctx.access.check() actually authorized the caller against). Every other org-mutation tool (member-add.ts, member-remove.ts, update.ts, delete.ts) has this exact guard; this one was missed.

Why it matters: ctx.access.check() verifies the caller's permission in ctx.organization (resolved from the URL slug), not in whatever organizationId the request body carries. Without the guard, a caller authorized for org A could pass organizationId: <org B> and have the tool operate against org B instead of the org the request was actually authorized for — the same scope-confusion bug class fixed in ORGANIZATION_UPDATE (#6541-era fix). The existing canAssignRole check against the target org's real membership row still gates privilege escalation, but doesn't stop the tool acting on an org outside the one ctx.access.check() validated.

Fix: add the identical if (organizationId !== ctx.organization?.id) throw ... guard already present in the sibling tools, plus a regression test asserting the mismatch is rejected before updateMemberRole is ever called.

Verify: cd apps/api && bun test src/tools/organization/member-update-role.test.ts

Locally ran: bun run fmt, bunx tsc --noEmit (apps/api), the targeted test above, and bunx oxlint on both changed files — all clean. Full CI validates the rest.


Summary by cubic

Fixes a missing org-scoping guard in ORGANIZATION_MEMBER_UPDATE_ROLE so callers can no longer act on an organization other than the one the request was authorized for. Previously the tool accepted an organizationId without checking it against the authenticated org, so a caller authorized for org A could pass org B's ID and the tool would operate on org B.

  • Adds the same organizationId !== ctx.organization?.id guard already present in member-add.ts, member-remove.ts, update.ts, and delete.ts.
  • Includes a regression test asserting the mismatch is rejected before updateMemberRole is called.

Written for commit 641419d. Summary will update on new commits.

Review in cubic

@pedrofrxncx
pedrofrxncx merged commit cde8229 into main Sep 4, 2026
33 checks passed
@pedrofrxncx
pedrofrxncx deleted the fix/member-update-role-org-scope-guard-w4 branch September 4, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant