Feb 25, 2026·6 min read·36 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.
The PHP Secure Communications Library (phpseclib) contains a Server-Side Request Forgery (SSRF) vulnerability due to an insecure default implementation of Authority Information Access (AIA) certificate chasing. This flaw allows remote, unauthenticated attackers to coerce applications validating user-supplied X.509 certificates into generating arbitrary outbound HTTP requests to internal networks or local interfaces.
A directory traversal vulnerability exists in the Microsoft .NET System.Formats.Tar library during archive extraction. When extracting a TAR archive using the TarFile.ExtractToDirectory API, the extraction engine improperly resolves symbolic links prior to file creation, allowing local unauthorized attackers to write or overwrite arbitrary files outside the target directory. This can lead to local tampering, privilege escalation, or arbitrary code execution.
A client-side HTML sanitization bypass vulnerability exists in the Bleach library where the formaction attribute is not recognized as a URI. This allows attackers to inject javascript: URIs when formaction is on the allowed list, resulting in Cross-Site Scripting (XSS).
A reflected DOM-based Cross-Site Scripting (XSS) vulnerability was identified in Nuxt's core <NuxtLink> component. Prior to the patched versions, the component failed to validate or sanitize the target URI schemes before directly rendering them into the 'href' attribute of native HTML anchor elements. An attacker who controls the input bound to the 'to' or 'href' properties can inject executable URI schemes, such as 'javascript:' or 'data:', leading to arbitrary script execution in the context of the user's browser session.
A state persistence vulnerability exists in Tornado's CurlAsyncHTTPClient component where pooled pycurl.Curl handles are reused across asynchronous requests without a complete state reset. Consequently, sensitive per-request configurations, such as client TLS certificates or proxy basic authentication credentials, persist on the shared handle. This behavior leads to subsequent requests leaking these credentials to unauthorized remote servers.
CVE-2026-48748 is a denial-of-service vulnerability in Netty's HTTP/3 codec (netty-codec-http3) occurring when QPACK dynamic tables are enabled but the blocked streams limit is not explicitly configured. A bug in limit checking and a memory leak in stream tracking allow unauthenticated remote attackers to exhaust the JVM heap memory and crash the server.