Skip to content
winfunc
Disclosure record · Cube

Presto and Trino filter interpolation bypasses row-level security

A MySQL string encoder broke Presto/Trino parameter boundaries after access-policy compilation

CubeDisclosedSource record

CVSS 3.1 base score

High
7.7/ 10

Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N

Record

Project
Cube
Severity
High7.7
CVE
None listed
Disclosed
Trace
3 steps

Summary

Source

POST /cubejs-api/v1/load handler

packages/cubejs-api-gateway/src/gateway.ts:344

Sink

PrestoDriver.queryPromised()

packages/cubejs-prestodb-driver/src/PrestoDriver.ts:267

An ordinary authenticated analytics user could inject Presto/Trino syntax through a semantic string filter, comment out the row-level predicate appended by Cube, and retrieve warehouse rows explicitly denied by the access policy.

Root cause. PrestoDriver.prepareQueryWithParams() used the MySQL-oriented sqlstring encoder, which escaped a quote as \'. Presto and Trino require doubled quotes, so the backend parsed the quote as the end of the literal after RLS compilation but before execution.

Remediation evidence. Cube acknowledged the reports and merged exact PR #11345 on 27 July 2026. The patch replaces wrong-dialect escaping in both the Presto and inherited Trino paths and adds quote-handling regression tests.

Severity

Attack vectorAV
Network
Attack complexityAC
Low
Privileges requiredPR
Low
User interactionUI
None
ScopeS
Changed
ConfidentialityC
High
IntegrityI
None
AvailabilityA
None

Metric values as published in the disclosure vector. Meters show how far each value raises exposure.

Source-to-sink trace

  1. Source · attacker-controlledpackages/cubejs-api-gateway/src/gateway.ts:344

    POST /cubejs-api/v1/load handler

  2. Step 01packages/cubejs-api-gateway/src/gateway.ts:344

    The authenticated REST request supplies a semantic query and attacker-controlled string filter value.

    typescript
    query: req.body.query
    
  3. Step 02packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

    Cube applies the user's row-level access policy and compiles a statement with a placeholder plus a separate values array.

    javascript
    const { query, values } = queryWithRlsFilters.buildSqlAndParams();
    
  4. Step 03packages/cubejs-prestodb-driver/src/PrestoDriver.ts:267

    The driver interpolates the value with MySQL quote rules and submits the resulting SQL text to Presto/Trino.

    typescript
    const sql = this.prepareQueryWithParams(query, values);
    return this.queryPromised(sql);
    
  5. Sinkpackages/cubejs-prestodb-driver/src/PrestoDriver.ts:267

    PrestoDriver.queryPromised()

Impact

Reported impact

The attacker can read policy-denied rows available to Cube's server-side warehouse identity, crossing tenant or user boundaries. Compatible UNION reads may widen disclosure, but this entry does not claim database writes or command execution.

Attack surface

Cube's authenticated data API when a model uses a Presto or Trino data source and row-level access policies protect tenant data.

Preconditions

The attacker has ordinary query access to one modeled member and can control a string filter. They need no administrator privileges or warehouse credentials.

Attack path

  1. 1

    Submit a normal semantic query with a filter such as active') OR true --.

  2. 2

    Allow Cube to append the attacker's RLS predicate and compile placeholders.

  3. 3

    The driver rewrites the embedded quote using a backslash.

  4. 4

    Presto/Trino treats the quote as syntax, evaluates the injected expression, and comments out the later RLS clause.

  5. 5

    The server returns rows outside the caller's tenant policy.

Proof of concept

Reproduction5 stages
  1. 01

    Environment setup

    Use an isolated Cube deployment connected to a test Presto or Trino warehouse containing tenant-A and tenant-B marker rows.

  2. 02

    Target configuration

    Configure a Cube access policy that restricts the attacker to tenant A while both tenants remain readable to the warehouse service account.

  3. 03

    Exploit delivery

    Send /cubejs-api/v1/load with an authenticated semantic query whose string filter contains active') OR true --.

  4. 04

    Expected response

    The vulnerable driver returns the tenant-B marker even though the compiled Cube policy should exclude it.

  5. 05

    Outcome

    PR #11345 emits SQL-standard doubled quotes, keeping the payload inside one string literal and preserving the appended RLS predicate.

Remediation

Guidance

Upgrade to a Cube release containing PR #11345. Keep values bound where possible; otherwise use a dedicated, tested encoder for the exact Presto/Trino literal grammar.

Before and after−1+3
SqlString.escape(value) // embedded quote becomes \'function prestoStringLiteral(value: string) {  return `'${value.replace(/'/g, "''")}'`;}
View original source record

Check the upstream record for the project's current remediation status.

Your codebase

Investigate the paths that matter in your codebase.

Winfunc can trace relevant code paths, preserve supporting evidence, and prepare remediation suggestions for engineering review within an agreed scope.