Skip to content

fix(auth): bind organization membership writes to exact credentials - #7538

Merged
bokelley merged 1 commit into
mainfrom
fix/organization-membership-exact-credential-writes
Sep 17, 2026
Merged

bokelley merged 1 commit into
mainfrom
fix/organization-membership-exact-credential-writes

Conversation

@bokelley

@bokelley bokelley commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This security change binds organization-membership writes to the exact authenticated credential and explicitly selected organization. It centralizes membership-management routes behind a transaction-scoped authorization fence while preserving current-main lifecycle, terminal-credential, grant, API-key, JWT, and onboarding behavior.

The immutable authentication snapshot now carries the exact identity-binding generation and compares it with fresh transaction state before provider or local effects. Membership webhooks retain exact-provider-membership and lifecycle fencing, serialize bounded provider snapshots ahead of the credential-revocation lock, and recheck lifecycle state before local effects.

This PR does not include the organization-deletion or organization-merge containment work from stacked child PRs #7560 and #7561.

Exact candidate

  • Base: 969ccf2e5274ddeaef36590963bf8ad1eab0576e
  • Head: acad5edcc2151ed3ca67aa9a7228ae6d94decc34
  • Tree: 007c0f3a9b4775476569fc309a445baeb71b7af6
  • Composition: one commit, 55 changed paths

Prepublication qualification

  • Database-backed affected suite: 524/524 passed across 19 files.
  • Focused/no-database suite: 777/777 passed across 21 files.
  • Full unmodified pre-commit hook: green.
    • Root and repository checks passed.
    • Server unit: 10,736 passed, 31 skipped across 643 files.
    • TypeScript and fixed-trace rollout-fixture typechecks passed.
  • Migration guard: 3/3 passed.
  • Addie tool inventory/portability: 249 tools across 69 sets, green.
  • Semgrep: 0 findings across 866 files.
  • Independent read-only exact-commit security/fidelity/execution review completed before publication.

Final qualification used controlled WorkOS doubles and an isolated PostgreSQL test database; no production credentials or production database were accessed.

Review and landing result

  • Exact-head ordinary CI passed, followed by a fresh successful Ladon review and native aao-secretariat[bot] approval on the exact head above.
  • GitHub's synthetic merge commit was fae357424b22dd83277f34a6395fd5810f1051e6, with exact parents 969ccf2e5274ddeaef36590963bf8ad1eab0576e and acad5edcc2151ed3ca67aa9a7228ae6d94decc34, and tree 007c0f3a9b4775476569fc309a445baeb71b7af6.
  • The guarded squash merge landed as 9d247db2e6e2af755951cba268b060425f246e2f, with sole parent 969ccf2e5274ddeaef36590963bf8ad1eab0576e and the exact reviewed tree.
  • Auto-merge and administrator bypass were not used. Child PRs fix(orgs): make organization deletion temporarily unavailable (#6827) #7560 and fix(orgs): contain organization merge and its operator bypasses (#6827) #7561 remain open and were not landed.

Comment thread server/src/http.ts Resolved
@bokelley
bokelley requested a review from a team September 16, 2026 18:24
@bokelley
bokelley marked this pull request as ready for review September 17, 2026 07:25
Comment thread server/src/routes/workos-webhooks.ts Resolved
aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Sep 17, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — server/app-only membership + auth hardening, no blocking findings.

What I checked:

  • Exact-credential membership fence (new organization-membership-mutation.ts +519, organization-membership-mutations.ts +465): fail-closed throughout — FOR UPDATE NOWAIT, 5s/no-retry enforcement client, lock_timeout=2s, finite typed error mapper. No Critical/High.
  • Auth-layer hardening (workos-jwt kid validation, 503-on-source-unavailable, cached/JWT user cloning) and the webhook re-read/exact-delete rewrite reviewed; no wire/protocol/schema/dist surface touched, so no changeset required.
  • high_risk: true but all high-risk-path matches are (modified) or (added) route files with no medium-or-higher finding on them — no deletions, no destructive change. Per the high-risk-flag reading rules, the flag alone is not escalation-worthy.

Medium findings:

  • server/src/routes/workos-webhooks.ts — holds organizations FOR UPDATE across default-client WorkOS calls with no txn lock_timeout; can pin the org row and a pooled connection under provider slowness.

Decision path: No critical/high (row 1 n/a). gated_paths: false (row 2 n/a). No (deleted) reasons (row 3 n/a). The single medium is not in data-loss/schema/infra category and is on a modified high-risk file — but row 5 requires a medium ON a modified high-risk file; the medium here is on workos-webhooks.ts which IS a modified high-risk match, so row 5 warrants a look. However this is a single medium; re-checking: row 5 fires when high_risk true AND any (modified) reason AND any medium finding exists. That condition is technically met by the webhook connection-hold concern.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean delta pass, no blocking or medium findings.

This is a subsequent review (prior outcome: approve). The only production change since the prior approve bounds the WorkOS webhook membership reconciliation while the org row is locked: SET LOCAL lock_timeout = '2s' before the FOR UPDATE, with all in-transaction provider reads routed through the fail-fast enforcement client (5s timeout, 0 retries). Contention fails closed (pg 55P03 → handler 500 → WorkOS redelivery + notifySystemError) with matching test coverage. No new findings and no prior blockers to re-surface.

Gate checks:

  • No no-auto-approve team match (HARD RULE not triggered).
  • gated_paths: false (row 2 not triggered).
  • high_risk: true, but reasons are (modified)/(added) only — no (deleted) (row 3 not triggered). No medium findings on the modified sensitive files, so rows 4 and 5 do not fire.
  • Prior decision was approve, not escalate (row 6 not triggered).
  • Zero medium findings (row 8 not triggered).

None of rows 1–8 fire → row 9: approve.

aao-secretariat[bot]
aao-secretariat Bot previously approved these changes Sep 17, 2026

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve.

Delta pass over the lock-budget correction (9d2febe→3085c09f). The three in-transaction WorkOS reads in upsertMembership now use the fail-fast enforcement client (5s timeout, maxRetries 0), and SET LOCAL lock_timeout='2s' bounds lock acquisition — a slow provider read no longer holds the org FOR UPDATE lock or lets contenders pile up. Rollback/release and no-local-mutation-on-failure behaviors are test-covered.

No critical/high/medium findings this run. The prior decision was already approve with no findings, so this is a net-neutral/clean subsequent pass.

high_risk is true, but the flagged files are server/src/routes/** and server/src/addie/** matches that are either newly added scaffolding or modified files with no reviewer concern (no (deleted) entries). No gated-paths gate (gated_paths: false), no no-auto-approve team match, no breaking protocol/schema surface touched (changes are server/platform-only, no static/schemas/source/** or dist/** edits). None of decision rows 1–8 fire; falls through to row 9.

@bokelley
bokelley force-pushed the fix/organization-membership-exact-credential-writes branch from 3085c09 to acad5ed Compare September 17, 2026 22:21
@bokelley
bokelley marked this pull request as ready for review September 17, 2026 22:31

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean pass, no blocking findings.

This is a server-only change (55 files) reworking organization membership authorization: the OrganizationMembershipMutation fence, fenced mutation routes, the WorkOS webhook rewrite, and supporting auth/db changes. The reviewer confirmed authority is bound to the exact credential/identity/epoch/membership with fail-closed rechecks before every provider and local effect, last-owner and self-mutation protections hold, and there is no schema/docs/dist/changeset surface touched.

Decision-table walk:

  • Row 1 (critical/high): no findings.
  • Row 2 (gated_paths): gated_paths is false — does not apply despite review_decision REVIEW_REQUIRED.
  • Row 3 (deleted high-risk path): no (deleted) reasons; matches are (modified)/(added).
  • Row 4 (medium data-loss/schema/infra): no medium findings.
  • Row 5 (high_risk modified + medium): high_risk is true and files are modified, but no medium finding exists.
  • Row 6 (sticky escalate): prior decision was approve, not escalate.
  • Row 7 (no-auto-approve team): no team match.
  • Row 8 (3+ medium): zero medium findings.
  • Row 9: approve.

high_risk is true, but per the flag-reading guidance it is a heuristic to look closer, not an auto-escalation trigger. The modified high-risk files carry no medium-or-higher concerns, so the modifications are presumed safe. Prior run on an earlier head also approved with no findings; this run confirms the same.

@bokelley
bokelley merged commit 9d247db into main Sep 17, 2026
34 checks passed
@bokelley
bokelley deleted the fix/organization-membership-exact-credential-writes branch September 17, 2026 22:42
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.

2 participants