CVE-2026-30944
StudioCMS has Privilege Escalation via Insecure API Token Generation
How AI Introduced This
The fix changes only the ordering of `availablePermissionRanks`, and the repository uses `availablePermissionRanks.indexOf(...)` to compare authorization levels when creating, updating, and revoking API tokens and user roles. In the bug-introducing commit, this array was first added in descending privilege order (`['owner','admin','editor','visitor','unknown']`), which makes numeric comparisons like `targetPerms >= userPerms` backwards and allows lower-privileged users to satisfy checks intended to block higher-privilege operations. Because the vulnerable rank ordering originated in this commit and was later corrected to ascending order, this commit introduced the vulnerability.
▶Bug-Introducing Commits(1)
feat(@withstudiocms/auth-kit): Part-1 new package (#735)
Tribunal Analysis
3 agents▶CONFIRMEDGPT-5.498%
The fix changes only the ordering of `availablePermissionRanks`, and the repository uses `availablePermissionRanks.indexOf(...)` to compare authorization levels when creating, updating, and revoking API tokens and user roles. In the bug-introducing commit, this array was first added in descending privilege order (`['owner','admin','editor','visitor','unknown']`), which makes numeric comparisons like `targetPerms >= userPerms` backwards and allows lower-privileged users to satisfy checks intended to block higher-privilege operations. Because the vulnerable rank ordering originated in this commit and was later corrected to ascending order, this commit introduced the vulnerability.
- •Fix commit changes `availablePermissionRanks` from `['owner','admin','editor','visitor','unknown']` to `['unknown','visitor','editor','admin','owner']` in `packages/@withstudiocms/auth-kit/src/types.ts`.
- •At the fixed revision, `packages/studiocms/frontend/pages/studiocms_api/_handlers/dashboard/apiTokens.ts` compares permissions via `const targetPerms = availablePermissionRanks.indexOf(tokenData.rank); const userPerms = availablePermissionRanks.indexOf(userData.permissionLevel); if (targetPerms >= userPerms) ...`, so array order defines authorization semantics.
- •The suspected BIC `341b59e3c775f619e9630c9044772ef0f16d1970` is the commit that introduced `packages/@withstudiocms/auth-kit/src/types.ts` with the incorrect descending order of `availablePermissionRanks`.
▶CONFIRMEDClaude Opus 4.692%
The BIC (341b59e3) created the `availablePermissionRanks` array in `packages/@withstudiocms/auth-kit/src/types.ts` with the order `['owner', 'admin', 'editor', 'visitor', 'unknown']`, placing the highest privilege ('owner') at index 0 and the lowest ('unknown') at index 4. Later code used `availablePermissionRanks.indexOf()` for permission comparisons assuming higher index = higher privilege, which inverted the permission hierarchy. This allowed lower-privileged users (e.g., 'unknown' at index 4) to pass permission checks that should have required higher privileges (e.g., 'owner' at index 0), enabling privilege escalation. The fix correctly reverses the array to `['unknown', 'visitor', 'editor', 'admin', 'owner']`. The BIC is the root cause because it introduced the incorrectly-ordered constant that was exported and consumed by permission-checking code.
- •The BIC introduced `availablePermissionRanks = ['owner', 'admin', 'editor', 'visitor', 'unknown']` with owner at index 0 and unknown at index 4
- •The fix reverses the order to `['unknown', 'visitor', 'editor', 'admin', 'owner']` so higher index = higher privilege
- •Permission checks use `availablePermissionRanks.indexOf()` with comparisons like `if (targetPerm >= callerPerm)` and `if (userPerms <= targetCurrentLevel)`, which assume higher index means higher privilege
- •With the old order, an 'unknown' user (index 4) would appear to have higher permissions than an 'owner' (index 0), enabling privilege escalation
- •The array was exported from auth-kit and consumed by multiple API handlers for authorization decisions
▶UNLIKELYGemini 3.1 Pro30%
Fallback verdict: Agent exhausted max turns without submitting a verdict.
yield* sdk.REST_API.tokens.delete({ tokenId: tokenID, userId: userID }); // without checking if the current user matches userID or has admin rights▶AI Signals(1)
| GitHub Copilot | Co-author trailer (generic) | Co-authored-by: Copilot | 70% |
▶Fix Commits(2)
▶References(6)
- https://github.com/withstudiocms/studiocms/security/advisories/GHSA-667w-mmh7-mrr4
- https://nvd.nist.gov/vuln/detail/CVE-2026-30944
- https://github.com/withstudiocms/studiocms/commit/9eec9c3b45523b635cfe16d55aa55afabacbebe3
- https://github.com/withstudiocms/studiocms/commit/f4a209fc090c90195e2419fff47b48a46eab7441
- https://github.com/withstudiocms/studiocms/releases/tag/studiocms%400.4.0
- https://github.com/withstudiocms/studiocms/releases/tag/studiocms@0.4.0