Skip to content

REST API Missing Rank Check Allows Admin to Create Peer Admin Accounts

Moderate
Adammatthiesen published GHSA-wj56-g96r-673q Mar 11, 2026

Package

npm studiocms (npm)

Affected versions

<=0.4.2

Patched versions

0.4.3

Description

Summary

The REST API createUser endpoint uses string-based rank checks that only block creating owner accounts, while the Dashboard API uses indexOf-based rank comparison that prevents creating users at or above your own rank. This inconsistency allows an admin to create additional admin accounts via the REST API, enabling privilege proliferation and persistence.

Details

The REST API handler in packages/studiocms/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts:1365-1378:

// REST API — only blocks creating 'owner'
if (newUserRank === 'owner' && rank !== 'owner') {
    return yield* new RestAPIError({
        error: 'Unauthorized to create user with owner rank',
    });
}

if (rank === 'admin' && newUserRank === 'owner') {
    return yield* new RestAPIError({
        error: 'Unauthorized to create user with owner rank',
    });
}

// Missing: no check preventing admin from creating admin
// newUserRank='admin' passes all checks

The Dashboard API handler in _handlers/dashboard/create.ts uses the correct approach:

// Dashboard API — blocks creating users at or above own rank
const callerPerm = availablePermissionRanks.indexOf(userData.permissionLevel);
const targetPerm = availablePermissionRanks.indexOf(rank);

if (targetPerm >= callerPerm) {
    return yield* new DashboardAPIError({
        error: 'Unauthorized: insufficient permissions to assign target rank',
    });
}

With availablePermissionRanks = ['unknown', 'visitor', 'editor', 'admin', 'owner']:

  • Admin (index 3) creating admin (index 3): 3 >= 3 = blocked in Dashboard
  • In REST API: no such check — allowed

PoC

# 1. Use an admin-level API token

# 2. Create a new admin user via REST API
curl -X POST 'http://localhost:4321/studiocms_api/rest/v1/secure/users' \
  -H 'Authorization: Bearer <admin-api-token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "rogue_admin",
    "email": "rogue@attacker.com",
    "displayname": "Rogue Admin",
    "rank": "admin",
    "password": "StrongP@ssw0rd123"
  }'

# Expected: 403 Forbidden (admin should not create peer admin accounts)
# Actual: 200 with new admin user created

Impact

  • A compromised or rogue admin can create additional admin accounts as persistence mechanisms that survive password resets or token revocations
  • Inconsistent security model between Dashboard API and REST API creates confusion about intended authorization boundaries
  • Note: requires admin access (PR:H), which limits practical severity

Recommended Fix

Replace string-based checks with indexOf comparison in packages/studiocms/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts:

// Before:
if (newUserRank === 'owner' && rank !== 'owner') { ... }
if (rank === 'admin' && newUserRank === 'owner') { ... }

// After:
const availablePermissionRanks = ['unknown', 'visitor', 'editor', 'admin', 'owner'];
const callerPerm = availablePermissionRanks.indexOf(rank);
const targetPerm = availablePermissionRanks.indexOf(newUserRank);

if (targetPerm >= callerPerm) {
    return yield* new RestAPIError({
        error: 'Unauthorized: insufficient permissions to assign target rank',
    });
}

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L

CVE ID

CVE-2026-32106

Weaknesses

Improper Privilege Management

The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor. Learn more on MITRE.

Credits