Skip to content

fix(rbac): enforce rank-ceiling on scoped-key mint (close escalation merged in #99)#114

Merged
servathadi merged 1 commit into
mainfrom
fix/rbac-rank-ceiling
Jun 11, 2026
Merged

fix(rbac): enforce rank-ceiling on scoped-key mint (close escalation merged in #99)#114
servathadi merged 1 commit into
mainfrom
fix/rbac-rank-ceiling

Conversation

@servathadi

Copy link
Copy Markdown
Contributor

Incident fix-forward: PR #99 merged WITHOUT its rank-ceiling fix (isolated worktree didn't push). Main shipped the identity BLOCK: a plain admin could mint another org-admin. This cherry-picks the fix (65b3c2c): rank-ceiling enforced (403 rank_ceiling when preset.role rank >= minter rank; admin can't mint admin), rank-max upsert (no audit-label divergence). Verified: 10 rank-ceiling refs, typecheck clean, 50/50 scoped-key tests, 811 suite green. Closes the #99 BLOCK; #106 (granular requireCapability gates) remains the next follow-up.

…n scoped-key mint

P0 BLOCK (identity-surface): mintScopedKey lacked a minter-rank-ceiling check.
A plain admin (rank 4) could mint another admin (rank 4) — lateral admin proliferation.
Fix: minterRank is now required in MintParams; the preset's role rank must be STRICTLY
LESS THAN minterRank or the call returns rank_ceiling (403 at the route layer).
Owner (5) can mint admin (4); admin (4) can mint lead/member/observer but not admin.

WARN (audit-label divergence): the INSERT OR IGNORE strategy allowed re-minting a
higher preset over an existing lower grant to silently no-op — the stored grant stayed
at the lower rank while the token label advertised a higher one. Fix: rank-max upsert —
read existing grant first; INSERT OR REPLACE only when the preset rank > existing rank;
skip the write and set grantUnchanged=true when the existing rank is already >=. The
show-once page surfaces a notice when the grant was unchanged.

Route (dashboard/index.ts): resolves minterRank via actorMaxRankOnScope before calling
mintScopedKey; maps rank_ceiling → 403; passes grantUnchanged to keysMintedBody.

Tests: 5 new cases (50 total in dashboard-keys.test.ts):
  admin minting admin preset → rank_ceiling
  owner minting admin preset → OK
  admin minting sales-rep/observer → OK
  rank-max upsert: sales-rep over observer → grant upgraded to member
  observer over existing lead → stays lead, grantUnchanged=true

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@servathadi servathadi merged commit bcd1abb into main Jun 11, 2026
5 checks passed
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