Feb 10, 2026·6 min read·24 visits
An authenticated attacker can escalate privileges by injecting a `securityContext` object into WebSocket messages or triggering a race condition in the API gateway. This allows bypassing Row-Level Security (RLS) and multi-tenant isolation, granting full admin access or data visibility across tenants.
Cube (formerly Cube.js) is the self-proclaimed 'semantic layer' for building data applications—a fancy way of saying it sits between your messy SQL databases and your pretty frontend charts. In versions prior to 1.5.13, Cube suffered from a catastrophic logic error in its WebSocket gateway and async handling. By simply asking nicely (read: injecting a JSON object), a low-privileged user could override their own security context. Even worse, a race condition in the promise chain allowed user contexts to 'bleed' into one another, meaning your request for 'My Sales' might accidentally return 'competitor_sales' if the server was busy enough. This is a classic case of trusting client input combined with the distinct misery of Node.js event loop management.
In modern data stacks, 'Semantic Layers' are the new hotness. They act as the single source of truth, translating abstract business logic (like 'Revenue') into concrete SQL queries. Cube is the leader in this space. It handles authentication, caching, and query orchestration. Ideally, it's the bouncer at the club, checking IDs and ensuring you only sit at the table you paid for.
But here's the thing about bouncers: if they are distracted or easily bribed, the whole security model collapses. Cube relies heavily on 'Security Contexts'—objects defining who you are and what you can see (e.g., tenant_id: 123). This context is usually derived from a cryptographically signed JWT. You trust the JWT, you trust the context.
CVE-2026-25958 reveals that Cube didn't just trust the JWT. It also trusted the WebSocket packet you just sent it. It’s the equivalent of the bouncer checking your ID, then asking, 'And what VIP level would you like to be today?' and actually writing it down on your wristband.
This vulnerability is a two-headed beast. The first head is WebSocket Parameter Pollution. When you connect to Cube via WebSockets, you send JSON messages to trigger data loads. The backend logic took the user's provided message and merged it into the internal state. The developers failed to sanitize the input for reserved keys like securityContext.
If you sent a payload containing securityContext: { isAdmin: true }, the application effectively said, 'Sure, seems legit,' and merged that flag into your active session. This allows for trivial privilege escalation. You aren't cracking a password; you're just politely informing the server that you are, in fact, the boss.
The second head is a Race Condition in the Async Boundary. In packages/cubejs-api-gateway/src/gateway.ts, specific core methods (like meta and sql) invoked response callbacks without properly awaiting the result. In the Node.js event loop, this created a 'broken promise chain'.
Because the request context wasn't strictly bound to the execution scope of the database query, high-concurrency traffic could cause Context Bleeding. The security context of User A (an Admin) could leak into the response processing of User B (a Viewer), accidentally serving privileged data to the wrong socket.
Let's look at the failure in the WebSocket handler. The code was iterating over the message parameters and blindly applying them. It lacked a 'strict' schema validation.
The Vulnerable Pattern (Simplified):
// Inside the WebSocket message handler
const processMessage = (message, connection) => {
// message.params comes directly from the user
const queryContext = {
...connection.userContext, // The real context from JWT
...message.params // The untrusted input overwriting it
};
// queryContext now has user-injected 'isAdmin: true'
return executeQuery(queryContext);
};The Fix (Commit 6271520):
The patch introduced zod schemas to strictly validate inputs. Instead of a spread operator that merges everything, the new code explicitly parses only allowed fields.
// The Fix: Strict Schema Validation
const LoadRequestSchema = z.object({
query: QuerySchema,
queryType: z.string().optional(),
// securityContext is notably ABSENT from the allowed schema
});
const safeParams = LoadRequestSchema.parse(message.params);
// Now safeParams only contains what the devs intended.Additionally, in gateway.ts (Commit 9e9f9d1), they had to fix the async bleeding.
Before:
this.loadImpl(options, (err, res) => {
// Callback hell leading to context loss
});After:
// Forcing the promise to resolve within the correct context scope
await this.loadImpl(options);By forcing the await, the AsyncLocalStorage context remains consistent throughout the lifecycle of the request.
To exploit this, you don't need fancy binary tools. You just need a WebSocket client and a valid low-privileged JWT. The goal is to bypass the Row-Level Security (RLS) that keeps tenants separate.
Step 1: Connect Establish a standard WebSocket connection to the Cube API. Authenticate with your low-privilege JWT.
Step 2: Craft the Payload
Construct a load message. The documentation says you should send a query. The exploit says you should send a query AND a securityContext.
{
"messageId": "1337",
"method": "load",
"params": {
"query": {
"measures": ["Orders.totalRevenue"],
"dimensions": ["Orders.createdAt"]
},
"securityContext": {
"u": {
"id": 1,
"roles": ["admin"],
"tenantId": "*"
}
}
}
}Step 3: Execution
Send the JSON. The server deserializes the message. The securityContext provided in params overrides the one extracted from your JWT. Cube generates the SQL. Instead of WHERE tenant_id = 'your_id', it generates WHERE 1=1 (or whatever the admin rule is).
Step 4: Profit The server streams back the financial data for every tenant on the platform. You have successfully democratized the data, whether they wanted you to or not.
This is a Critical Severity issue for any multi-tenant SaaS application using Cube. The impact is not just data leakage; it's total isolation failure.
order parameter (CWE-89), this could escalate further into blind SQL injection via the metadata generation layer.The business impact? If you are a B2B SaaS provider, your customers' competitors just got access to their sales numbers. Trust is the first casualty.
Remediation is straightforward but urgent. You must upgrade the Cube core packages.
Action Items:
1.5.13, 1.4.2, or 1.0.14 immediately. These versions introduce the Zod schema validation that strips the malicious payload.securityContext key in the parameters. This key should effectively never come from the client side.CUBEJS_WEB_SOCKETS=false. This reduces the attack surface significantly, as the REST API uses a different parsing path that was less susceptible to this specific pollution attack.Developer Lesson: Never use the spread operator (...) on user input when building security contexts. It's concise, it's pretty, and it's dangerous.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Cube Cube Dev | 0.27.19 - < 1.0.14 | 1.0.14 |
Cube Cube Dev | 1.1.0 - < 1.4.2 | 1.4.2 |
Cube Cube Dev | 1.5.0 - < 1.5.13 | 1.5.13 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-807 |
| Attack Vector | Network (WebSocket) |
| CVSS | 7.7 (High) |
| Impact | Privilege Escalation / Info Disclosure |
| Exploit Status | PoC Available |
| Fix Complexity | Low (Version Upgrade) |
The application relies on untrusted inputs to make security decisions, specifically allowing client-side overriding of the security context.
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.