Feb 25, 2026·6 min read·3 visits
If you use dynamic master keys (functions) in Parse Dashboard, your cache is confused. If an admin logs in, the 'God Mode' key is cached. If a read-only user logs in immediately after, they get served that same God Mode key from the cache. Patch to 9.0.0-alpha.8 immediately.
A critical race condition and cache collision vulnerability exists in Parse Dashboard versions 7.3.0-alpha.42 through 9.0.0-alpha.7. The flaw lies within the configuration caching mechanism for dynamic master keys. When an application configures its `masterKey` as a function (for rotation or retrieval purposes), the dashboard caches the result. However, the cache key failed to differentiate between a full administrative session and a read-only session. This allows a read-only user to inherit the cached full master key if an administrator has recently accessed the dashboard, leading to immediate privilege escalation and potential data destruction.
Parse Server is the spiritual successor to the mobile backend-as-a-service throne, and Parse Dashboard is its cockpit. It allows developers to manage users, view analytics, and manipulate database entries with a nice GUI. To do this, the dashboard needs the Master Key—a cryptographic string that bypasses all Access Control Lists (ACLs) and Class Level Permissions (CLPs). It is the "sudo" of the Parse ecosystem.
Usually, this key is a static string in a config file. But enterprise environments are complex; they need key rotation, dynamic retrieval from vaults, or environment-specific logic. So, Parse Dashboard allows the masterKey to be defined as a function rather than a string. This function runs, fetches the key, and returns it.
Here is the problem: Running a function every single time a request hits the dashboard is expensive. Latency kills the user experience. So, naturally, the developers decided to cache the result. And therein lies the tragedy. They cached the result of the permission check, but they forgot to include the context of who asked for it.
The vulnerability is a classic case of CWE-1289: Improper Validation of Unsafe Equivalence. In computer science, naming things is one of the two hardest problems (alongside cache invalidation and off-by-one errors). In this case, the developers failed at both naming and cache validation.
When the dashboard initializes a session for a specific App ID, it checks if the masterKey is a function. If it is, it calls ConfigKeyCache.get. The fatal flaw was hardcoding the identifier for this cache entry to the string literal 'masterKey'.
This means the cache looked like this:
"my-app-id" + "masterKey" = "ACTUAL_SECRET_KEY"
The code did not care if the person requesting the key was the CTO with full write access or an intern with a read-only account. It simply asked: "Do I have a cached value for 'masterKey'? Yes? Here you go."
If an Admin logs in, the masterKey function resolves to the Full Access Key, and it gets cached. If a Read-Only user logs in five seconds later, the system sees the valid cache entry and hands them the Full Access Key. Suddenly, the intern is the CTO.
Let's look at the diff. It’s painful in its simplicity. The vulnerable code blindly trusted that if a key was cached, it was the right key for the current user.
Vulnerable Code (Before):
// Inside app.js logic
if (typeof app.masterKey === 'function') {
// The second argument 'masterKey' is the cache identifier
app.masterKey = await ConfigKeyCache.get(
app.appId,
'masterKey', // <--- THE BUG. Static string.
app.masterKeyTtl,
app.masterKey
);
}When the patch landed in 9.0.0-alpha.8, the fix was to split the cache universe into two parallel dimensions: one for the gods (admins) and one for the mortals (read-only users).
Fixed Code (After):
// The fix introduces context awareness
const cacheKey = matchingAccess.readOnly ? 'readOnlyMasterKey' : 'masterKey';
if (typeof app.masterKey === 'function') {
app.masterKey = await ConfigKeyCache.get(
app.appId,
cacheKey, // <--- Dynamic string based on privilege
app.masterKeyTtl,
app.masterKey
);
}By simply checking matchingAccess.readOnly and changing the cache key string, the collision is impossible. The Admin gets a value from the masterKey slot, and the Read-Only user gets a value from the readOnlyMasterKey slot.
This is a Passive-Aggressive Exploit. You don't hammer the server with buffer overflows; you just wait. The attack vector requires a Read-Only account, which is common in larger organizations (e.g., support staff, auditors, or junior devs).
Here is the attack chain:
masterKey function, resolves the Full Key, and caches it under appId:masterKey for the duration of the TTL (Time-To-Live)./apps/:appId/agent endpoint or use the dashboard's API to delete classes, drop database tables, or exfiltrate the entire _User table.This isn't just an information leak; it is a total compromise of the application's integrity. In the Parse ecosystem, the Master Key is absolute. It ignores all security rules.
DELETE request to the _Schema endpoint, wiping out entire collections.The remediation is straightforward but urgent. You must upgrade to parse-community/parse-dashboard@9.0.0-alpha.8 or later.
If you are stuck on an older version and cannot upgrade (perhaps due to breaking changes in the alpha branch), you have two mitigation options:
masterKey configuration in parse-dashboard-config.json to a static string. If it's a string, the caching logic is bypassed entirely.agent object from your configuration. However, this does not fix the underlying privilege escalation, it just removes one convenient gun from the attacker's hand.The official patch not only fixes the cache key name but also hardcodes permissions for read-only users in the Agent endpoint to prevent them from authorizing write actions, adding a defense-in-depth layer.
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
parse-dashboard parse-community | >= 7.3.0-alpha.42 < 9.0.0-alpha.8 | 9.0.0-alpha.8 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1289 (Improper Validation of Unsafe Equivalence) |
| CVSS v4.0 | 7.0 (High) |
| Attack Vector | Network (Remote) |
| Attack Complexity | High (Requires timing/race condition) |
| Privileges Required | Low (Read-only account) |
| Exploit Maturity | PoC / Functional |
The software compares two items to determine if they are equivalent, but the comparison is performed in a way that allows unsafe items to be treated as equivalent to safe items.