Presto and Trino filter interpolation bypasses row-level security
A MySQL string encoder broke Presto/Trino parameter boundaries after access-policy compilation
CVSS 3.1 base score
HighVector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
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
- Source · attacker-controlledpackages/
cubejs-api-gateway/ src/ gateway.ts:344 POST /cubejs-api/v1/load handler
- 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 - 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(); - 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); - 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
Submit a normal semantic query with a filter such as
active') OR true --. - 2
Allow Cube to append the attacker's RLS predicate and compile placeholders.
- 3
The driver rewrites the embedded quote using a backslash.
- 4
Presto/Trino treats the quote as syntax, evaluates the injected expression, and comments out the later RLS clause.
- 5
The server returns rows outside the caller's tenant policy.
Proof of concept
- 01
Environment setup
Use an isolated Cube deployment connected to a test Presto or Trino warehouse containing tenant-A and tenant-B marker rows.
- 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.
- 03
Exploit delivery
Send
/cubejs-api/v1/loadwith an authenticated semantic query whose string filter containsactive') OR true --. - 04
Expected response
The vulnerable driver returns the tenant-B marker even though the compiled Cube policy should exclude it.
- 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.
SqlString.escape(value) // embedded quote becomes \'function prestoStringLiteral(value: string) { return `'${value.replace(/'/g, "''")}'`;}
Check the upstream record for the project's current remediation status.
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.
