GitHub Advisoryadvisory · npm

GHSA-xvf4-ch4q-2m24 StudioCMS REST getUsers Exposes Owner Account Records to Admin Tokens

LOW Published 2026-03-16 Modified 2026-03-18 Official page ↗
Aliases
CVE-2026-32638
Ecosystem
npm
Packages
studiocms
Severity
Low
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
Weaknesses
CWE-639
Reviewed
2026-03-16

Affected packages

• npm studiocms: < 0.4.4 → fixed in 0.4.4

Description

Summary The REST API `getUsers` endpoint in StudioCMS uses the attacker-controlled `rank` query parameter to decide whether owner accounts should be filtered from the result set. As a result, an admin token can request `rank=owner` and receive owner account records, including IDs, usernames, display names, and email addresses, even though the adjacent `getUser` endpoint correctly blocks admins from viewing owner users. This is an authorization inconsistency inside the same user-management surface. Details Vulnerable Code Path File: `D:/bugcrowd/studiocms/repo/packages/studiocms/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts`, lines 1605-1647 ```ts .handle( 'getUsers', Effect.fn( function* ({ urlParams: { name, rank, username } }) { if (!restAPIEnabled) { return yield* new RestAPIError({ error: 'Endpoint not found' }); } const [sdk, user] = yield* Effect.all([SDKCore, CurrentRestAPIUser]); if (user.rank !== 'owner' && user.rank !== 'admin') { return yield* new RestAPIError({ error: 'Unauthorized' }); } const allUsers = yield* sdk.GET.users.all(); let data = allUsers.map(...); if (rank !== 'owner') { data = data.filter((user) => user.rank !== 'owner'); } if (rank) { data = data.filter((user) => user.rank === rank); } return data; }, ``` The `rank` variable in `if (rank !== 'owner')` is the request query parameter, not the caller's privilege level. An admin can therefore pass `rank=owner`, skip the owner-filtering branch, and then have the second `if (rank)` branch return only owner accounts. Adjacent Endpoint Shows Intended Security Boundary File: `D:/bugcrowd/studiocms/repo/packages/studiocms/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts`, lines 1650-1710 ```ts const existingUserRankIndex = availablePermissionRanks.indexOf(existingUserRank); const loggedInUserRankIndex = availablePermissionRanks.indexOf(user.rank); if (loggedInUserRankIndex ' ``` Expected behavior: • owner records should be excluded for admin callers, consistent with `getUser` Actual behavior: • the response contains owner user objects, including email addresses and user IDs Local Validation of the Exact Handler Logic I validated the filtering logic locally with the same conditions used by `getUsers` and `getUser`. Observed output: ```json { "admin_getUsers_rank_owner": [ { "email": "[email protected]", "id": "owner-1", "name": "Site Owner", "rank": "owner", "username": "owner1" } ], "admin_getUser_owner": "Unauthorized to view user with higher rank" } ``` This demonstrates the authorization mismatch clearly: • bulk listing with `rank=owner` exposes owner records • direct access to a single owner record is denied Impact • Owner Account Enumeration: Admin tokens can recover owner user IDs, usernames, display names, and email addresses. • Authorization Boundary Bypass: The REST collection endpoint bypasses the stricter per-record rank check already implemented by `getUser`. • Chaining Value: Exposed owner contact data can support phishing, account-targeting, and admin-to-owner pivot attempts in deployments that treat owner identities as higher-trust principals. Recommended Fix Apply rank filtering based on the caller's role, not on the request query parameter, and reuse the same privilege rule as `getUser`. Example fix: ```ts const loggedInUserRankIndex = availablePermissionRanks.indexOf(user.rank); data = data.filter((candidate) => { const candidateRankIndex = availablePermissionRanks.indexOf(candidate.rank); return loggedInUserRankIndex > candidateRankIndex; }); if (rank) { data = data.filter((candidate) => candidate.rank === rank); } ``` At minimum, replace: ```ts if (rank !== 'owner') { data = data.filter((user) => user.rank !== 'owner'); } ``` with a check tied to `user.rank` rather than the query parameter.

Related

Alias · CVE (1)

  • CVE-2026-32638 StudioCMS is a server-side-rendered, Astro native, headless content management system. vulnerability

Weakness · CWE (1)

  • CWE-639 Authorization Bypass Through User-Controlled Key weakness

References