EnxDev commented on PR #43111:
URL: https://github.com/apache/superset/pull/43111#issuecomment-5340888749

   ## EnxDev's Review Agent โ€” apache/superset#43111 ยท HEAD 5bec901
   
   **comment** โ€” right direction and the vectors it does cover are handled 
carefully, but the control is bypassed by omitting `slice_id`, and two 
legitimate guest flows now 403.
   
   On the earlier bot comments: the multi-query "predicate transfer" flag is a 
non-issue (all queries in a context share one datasource and predicates only 
restrict rows โ€” the docstring at `manager_test.py:3876` states this correctly), 
and the missing end-to-end coverage is addressed by 
`test_raise_for_access_guest_user_sql_filter_injection_blocked`. CI is green.
   
   ### ๐Ÿ”ด Functional
   
   - **`superset/security/manager.py:1403-1410`** ยท _High_ โ€” the fix is 
bypassed by dropping `slice_id`. A guest POSTs `/api/v1/chart/data` with 
`form_data: {"dashboardId": N}` (no `slice_id`, no `chart_id`, no `type: 
NATIVE_FILTER`) and arbitrary `extras.where`: `slice_` stays `None` 
(`query_context_factory.py:64-68`), so `query_context_modified` takes the 
chartless branch and `_native_filter_request_modified` returns `False` at its 
marker check (`manager.py:797-800`) โ€” the new check never runs. Datasource 
access is still granted, via `has_drill_access` (`manager.py:2076-2081`: 
`slice_id is None and chart_id is None and datasource in 
dashboard.datasources`) plus `can_access_dashboard`. So the exact attack in the 
PR summary still executes against any dataset on the embedded dashboard, 
including blind exfiltration through subqueries in the WHERE clause. Related: 
the new comment "these paths are still protected by datasource-access checks in 
`raise_for_access`" is not accurate โ€”
  those checks gate *which dataset* is queried, not *what SQL* runs against it 
(`_native_filter_request_modified`'s docstring makes the same claim). Constrain 
`extras.where`/`having` and adhoc `filter[].col` on the chartless path against 
the charts of the dashboard in `form_data["dashboardId"]`, or reject extras 
that derive from no chart on it. **regression test:** guest `raise_for_access` 
with `form_data={"dashboardId": 1}`, no `slice_id`, `extras={"where": "1=1"}` โ†’ 
must raise.
   
   - **`superset/security/manager.py:1224-1229`** ยท _High_ โ€” cross-filtering 
from a custom-SQL dimension now 403s the other charts. `getCrossFilterDataMask` 
emits `{col, op, val}` carrying the **source** chart's raw `QueryFormColumn` 
(`plugin-chart-echarts/src/utils/eventHandlers.ts:67-81`), which is an adhoc 
dict whenever that dimension is Custom SQL, and `buildQueryObject` appends it 
to every in-scope chart's `filters` (`buildQueryObject.ts:91`). `allowed` is 
built only from the **target** chart, so unless the target happens to store the 
same expression the guest gets "Guest user cannot modify chart payload". Before 
this PR an adhoc col that didn't resolve degraded gracefully 
(`rejected_adhoc_filters_columns`, `models/helpers.py:4361-4368`); now it's a 
hard 403. Allow adhoc `col.sqlExpression` values found on any chart of the 
requesting dashboard. **regression test:** stored chart B without the 
expression + `filter[0].col.sqlExpression` = chart A's dimension, same 
`dashboardId` 
 โ†’ not modified.
   
   - **`superset/security/manager.py:1216-1222`** ยท _Medium_ โ€” the async 
results fetch compares normalized SQL against the raw stored SQL. 
`QueryObject._sanitize_filters` rewrites `extras["where"/"having"]` in place 
(`common/query_object.py:342-380`): Jinja is rendered when 
`ENABLE_TEMPLATE_PROCESSING` is on, and `sanitize_clause` re-renders any clause 
containing a comment (`sql/parse.py:2425-2437`). `get_payload_result` then 
merges `query.to_dict()` into `cache_values["queries"]` and caches it 
(`common/query_context_processor.py:516-528`), and the guest's `GET 
/api/v1/chart/data/<cache_key>` rebuilds from that cached value and re-runs 
`raise_for_access` (`charts/data/api.py:411-417`). With `GLOBAL_ASYNC_QUERIES` 
on, a chart whose saved Custom SQL filter contains `--` or Jinja passes the 
POST and then 403s on the results fetch โ€” the chart renders as an error for the 
guest. Normalize both sides before comparing (run the stored expression through 
`sanitize_clause` too), or skip th
 e SQL comparison when the context was rehydrated from the query-context cache. 
**regression test:** saved filter `a > 0 -- note`, re-validate with the 
sanitized `(a > 0 /* note */)` โ†’ not modified.
   
   ### ๐ŸŸก Should-fix
   
   - **`tests/unit_tests/security/manager_test.py`** โ€” the `\n` strip added in 
`_split_extras_clauses:1142` (in response to review feedback) has no test. Add 
the case it exists for: stored `sqlExpression = "a > 0 -- x"`, request 
`extras.where = "(a > 0 -- x\n)"` โ†’ allowed. Without it the next refactor 
silently drops comment handling.
   
   ### ๐Ÿ”ต Nits
   
   - `superset/security/manager.py:1206-1214` โ€” the docstring's `) AND (` 
caveat only fails closed for charts **with** a stored `query_context`; the 
full-composed fallback is collected solely from stored query contexts 
(`_add_allowed_sql_from_query_context:1155-1159`), so a chart with 
`query_context = NULL` and such an expression 403s. Worth saying so, since NULL 
query contexts are common.
   
   ### ๐Ÿ™Œ Praise
   
   - `superset/security/manager.py:1120-1143` โ€” reversing `sanitizeClause`'s 
parenthesis wrapping and its `--` newline, and allowing the `1 = 0` 
required-filter sentinel, is exactly the frontend detail this check needed to 
not break real dashboards.
   
   <!-- enxdev-review-agent:5bec901 -->
   _Reviewed by EnxDev's Review Agent โ€” @EnxDev ยท HEAD 5bec901._
   


-- 
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]

Reply via email to