fix(embedded): allow guest users to sort by visible columns - #37371
Conversation
Code Review Agent Run #d2ccfeActionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Response to codeant-ai bot reviewThe bot's suggestion is incorrectThe bot suggested supporting # superset/superset_typing.py:51-57
class AdhocMetric(TypedDict, total=False):
column: AdhocMetricColumn | None # ← DICT or None, NEVER string!
# superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts
export interface AdhocMetricSimple {
column: { column_name?: string, ... }; // ← Always DICT
}Data Flow AnalysisKey point: However, added defensive barriers anywayEven though the bot's specific scenario is invalid, applied fail-closed defensive coding. This protects against malformed API requests, 500 errors, and potential bypasses. What added1. Validate orderby is a list ( if form_orderby is not None and not isinstance(form_orderby, list):
return True # block invalid formatAttack prevented: form_data = {"orderby": "malicious"} # string, not list
# Without barrier: iterates chars "m","a","l"... all skip → PASSES!
# With barrier: blocked immediately2. Validate each element is tuple/list Similar patterns in Superset codebaseOur barriers follow existing Superset patterns:
Why defensive barriers even if bot was wrong
Tests added (20 new tests)
|
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Code Review Agent Run #442218Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #37371 +/- ##
==========================================
- Coverage 64.60% 64.59% -0.01%
==========================================
Files 2684 2684
Lines 148192 148285 +93
Branches 34138 34167 +29
==========================================
+ Hits 95738 95787 +49
- Misses 50711 50743 +32
- Partials 1743 1755 +12
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Fixed in 81e9859ruff C901: Function too complexProblem: Fix: Extracted helper function |
Response to codeant-ai bot suggestionsBoth suggestions are incorrect per Superset's type system (see previous analysis). 1.
|
Code Review Agent Run #5fc97bActionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
|
Thanks for the thorough root-cause writeup @YuriyKrasilnikov. It's gone conflicting (again, sorry), so we'll need a rebase to get it merged, but we're getting better at staying on top of all these PRs these days. Since this loosens guest-user query validation it wants a careful security pass, so CC @dpgaspar @mistercrunch, and myself once it's green, and/or reach out on Slack. |
|
Sorry about the confusion on the Issue... I'll try to rebase and resolve conflicts here, so we can get this through and close the issue for real! |
Fixes apache#37061 Guest users in embedded dashboards can now sort table columns that are visible in the chart. Sorting by hidden columns or SQL expressions remains blocked for security. Changes: - Add FieldMapping TypedDict for extensible field configuration - Add _get_visible_columns() to extract columns/groupby/metrics - Add _extract_orderby_column_name() to normalize orderby format - Add _orderby_whitelist_compare() for whitelist validation - Add _default_field_compare() to reduce function complexity - Refactor query_context_modified() loop to use explicit variables - Fix variable shadowing bug (key reused in nested loop) - Add 3 tests for whitelist behavior
Add fail-closed defensive barriers to prevent malformed input from bypassing security checks or causing 500 errors. Changes: - _orderby_whitelist_compare(): validate orderby is list, each element is tuple/list, and not empty before processing - _extract_orderby_column_name(): validate nested column is dict - Added 20 unit tests covering valid formats and invalid edge cases Why barriers are needed: 1. Security-critical code should be fail-closed (block unknown, not pass) 2. Schema accepts fields.Raw() which doesn't validate structure 3. Prevents 500 errors on malformed input from API Example attack prevented: orderby: "malicious_string" # string instead of list Without barrier: iterates over characters, all skip, check passes With barrier: blocked immediately (fail-closed) Follows Superset defensive coding patterns: - isinstance checks before usage - Early return on invalid data - Comments explaining barrier purpose - No logging (consistent with security/ style)
Extract helper function to reduce cyclomatic complexity of _orderby_whitelist_compare from 12 to below 10 (ruff C901).
81e9859 to
0207a89
Compare
Two fixes made while rebasing this PR onto current master and reviewing it against the issue: 1. Reconcile the orderby visible-column whitelist with the native-filter time-grain handling on master. An orderby entry is allowed when it sorts by a visible column OR matches an entry the chart already sorts by (compared via freeze_value, which strips the guest-overridable timeGrain). Without this, a guest re-sending the chart's temporal x-axis orderby with a different grain was flagged as tampering (regressed test_query_context_modified_time_grain_in_orderby). 2. Include `all_columns` in the visible-column set. The Table plugin's raw "Query mode" stores its columns under `all_columns`, so raw-records tables (a common trigger of the reported guest sort error) would otherwise have all sorting blocked. Hidden columns and adhoc SQL expressions remain blocked (fail-closed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0207a89 to
aef22bf
Compare
Honor Table column_config visibility when deriving guest-sortable columns. Use Superset label helpers for column and metric labels so adhoc SIMPLE metrics without custom labels match their result keys. Require new guest orderby entries to be [term, bool] and block malformed SIMPLE metric dicts.
Code Review Agent Run #ca7b5dActionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
|
@rusackas thanks again for rebasing this and for the security-review guidance. I pushed one more pass in b68d882 and the PR is green now, including I re-traced the guest sorting path from the Table frontend down to backend validation and tightened the security boundary a bit more:
Local targeted validation: Also asking @dpgaspar @mistercrunch to take a look at this PR now that CI is green, since it may loosens guest-user query validation. |
|
Thanks for tackling this! Guest column sorting for embedded dashboards was since merged in #41218, which looks to supersede this (and the branch now conflicts with master), so I think it can be closed. Appreciate the work — the sortable-column handling here was nicely defensive. |
fd250de to
9f1aacc
Compare
Code Review Agent Run #029dc3Actionable Suggestions - 0Filtered by Review RulesBito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Code Review Agent Run #bcb008Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Code Review Agent Run #bcb008Actionable Suggestions - 0Filtered by Review RulesBito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
sha174n
left a comment
There was a problem hiding this comment.
Following up on my earlier comment: please disregard the "close as superseded" note. You've rebased onto the merged #41218 and reworked this to limit guest-initiated sorting to the chart's visible result columns (excluding those marked column_config: {visible: false}), while still replaying an owner's stored orderby. That's a solid defense-in-depth improvement on top of #41218, and the distinction between replaying a stored sort versus a guest changing its direction is nicely handled. Coverage looks thorough and CI is green. LGTM, and thanks for pushing it forward.
Summary
Fixes #37061: Guest users in embedded dashboards can now sort table columns.
Before: Clicking any column header →
"Guest user cannot modify chart payload"After: Sorting by visible columns works; hidden columns and SQL injection still blocked.
Problem Analysis
Root Cause
query_context_modified()treated orderby identically to metrics/columns:Issue: User clicks column → frontend sends new orderby →
orderby ≠ stored_orderby→ blocked.Why This Is Wrong
Sorting is navigation, not data access expansion.
Security Research
Before implementing, analyzed attack vectors:
Attack Vector Analysis
ORDER BY random(),sleep(5)expressionType: "SQL"ORDER BY credit_card_numberreveals rankingIndustry Standard
Mathematical Model
Architecture Decision
Why Not Just Remove orderby Check?
Rejected because: Opens SQL injection and data exfiltration vectors.
Why Not Frontend-Only Sorting?
Rejected because: Client-side sort on 1000 rows ≠ database sort on 100000 rows. Wrong results.
Why Comparator Pattern?
During implementation, discovered a bug in existing code:
This bug affects iterations 2-4 of the outer loop.
Solution: Refactor to explicit variables + custom comparator for orderby:
Why TypedDict?
Implementation Details
New Functions
_get_visible_columns(chart)set[str]_extract_orderby_column_name(item)str | None_orderby_whitelist_compare(ctx, chart, visible)bool(True = block)_default_field_compare(...)boolWhy
_extract_orderby_column_nameReturns None for SQL?Reason: SQL expressions can contain:
random()— non-deterministic, DoS potentialpg_sleep(5)— timing attack(SELECT password FROM users LIMIT 1)— data exfiltrationWhy Check Both form_data AND queries?
Reason: Attacker could send valid
form_data.orderbybut inject maliciousquery.orderby. Both must be validated.Why
equiv_fieldInstead ofkey?Reason: Python loop variables leak into outer scope. Reusing
keycorrupted subsequent iterations.Changes Summary
superset/security/manager.pytests/unit_tests/security/manager_test.pyNew Tests
test_..._visible_column_allowedtest_..._hidden_column_blockedcredit_card_numbertest_..._direction_change_allowedExisting
test_query_context_modified_orderby(SQL injection) continues to pass.Backward Compatibility
How To Test
Checklist