Skip to content

fix(security): reject unknown fields on guest-token RLS rules#41217

Open
rusackas wants to merge 2 commits into
masterfrom
fix/guest-token-rls-strict-validation
Open

fix(security): reject unknown fields on guest-token RLS rules#41217
rusackas wants to merge 2 commits into
masterfrom
fix/guest-token-rls-strict-validation

Conversation

@rusackas

Copy link
Copy Markdown
Member

SUMMARY

RlsRuleSchema (used to validate the rls rules in POST /api/v1/security/guest_token/) inherits from PermissiveSchema, whose Meta.unknown = EXCLUDE silently drops any field it doesn't recognize. So a guest-token RLS rule that uses a mistyped or legacy scope key — most commonly datasource: { id, type } (a leftover from older payloads) instead of the documented dataset: <int> — has that key stripped during deserialization. The resulting rule has no dataset.

SecurityManager.get_guest_rls_filters() treats a rule with no dataset as global (if not rule.get("dataset"), superset/security/manager.py), so the clause ends up applied to every dataset the embedded resource can reach instead of the single dataset the caller intended. The visible symptom is confusing query errors (e.g. column "…" does not exist when the clause lands on an unrelated dataset), and the rule's effective scope silently differs from what the integrator configured.

This makes RlsRuleSchema strict (Meta.unknown = RAISE) so an unexpected field raises a ValidationError (HTTP 400) that names the offending field, before a token is ever issued — instead of quietly producing a global rule. This:

  • Aligns runtime validation with the documented RlsRule contract (the OpenAPI spec advertises only dataset and clause).
  • Surfaces caller mistakes immediately rather than at query time on an unrelated dataset.
  • Leaves valid rules untouched — both dataset-scoped ({"dataset": 41, "clause": "…"}) and intentionally global ({"clause": "…"}) rules still load.
  • Keeps the rest of the guest-token payload (GuestTokenCreateSchema, UserSchema, ResourceSchema) permissive, so integrator-specific extra fields elsewhere are unaffected.

Framed as input-validation hardening / DX, not a privilege-escalation fix: the guest_token endpoint is called by a trusted integrator holding can_grant_guest_token, and RLS clauses are additive restrictions — so the impact is incorrect/over-broad rule scoping and confusing errors, not a Superset access-control bypass.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — API-only change.

TESTING INSTRUCTIONS

Unit tests added in tests/unit_tests/security/api_test.py:

  • test_rls_rule_schema_accepts_dataset_scoped_rule{"dataset": 41, "clause": "…"} still loads.
  • test_rls_rule_schema_accepts_global_rule{"clause": "…"} (no dataset) still loads.
  • test_rls_rule_schema_rejects_unknown_scope_key{"datasource": {…}, "clause": "…"} now raises ValidationError naming datasource.
  • test_rls_rule_schema_rejects_unknown_fields — any other unknown field is rejected.
  • test_rls_rule_schema_requires_clauseclause remains required.
pytest tests/unit_tests/security/api_test.py -v

Manual: POST /api/v1/security/guest_token/ with an rls entry using datasource instead of dataset now returns HTTP 400 pointing at the datasource field, instead of issuing a token whose rule is silently global.

ADDITIONAL INFORMATION

This tightens an API contract: integrators that were sending extra fields inside RLS rules (previously dropped) will now get a 400. Documented in UPDATING.md.

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

🤖 Generated with Claude Code

RlsRuleSchema inherited from PermissiveSchema, which silently drops
unknown fields. A guest-token rls rule that used a mistyped or legacy
scope key -- most commonly datasource instead of dataset -- therefore
had that key stripped during deserialization, leaving a rule with no
dataset. get_guest_rls_filters treats a rule with no dataset as global,
so the clause was applied to every dataset the embedded resource can
reach rather than the single dataset the caller intended.

Make RlsRuleSchema strict (Meta.unknown = RAISE) so an unexpected field
raises a ValidationError (HTTP 400) before a token is issued, instead of
producing a silently-global rule. This aligns runtime validation with
the documented RlsRule contract (dataset and clause). Valid
dataset-scoped and global rules are unaffected; the rest of the
guest-token payload remains permissive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dosubot dosubot Bot added api Related to the REST API authentication:row-level-security Related to Row Level Security risk:breaking-change Issues or PRs that will introduce breaking changes labels Jun 19, 2026
@bito-code-review

bito-code-review Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #1e90bd

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 89678dd..89678dd
    • superset/security/api.py
    • tests/unit_tests/security/api_test.py
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.36%. Comparing base (79cfe4d) to head (ee21f35).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #41217      +/-   ##
==========================================
- Coverage   64.36%   64.36%   -0.01%     
==========================================
  Files        2651     2651              
  Lines      144812   144814       +2     
  Branches    33417    33417              
==========================================
- Hits        93208    93205       -3     
- Misses      49935    49938       +3     
- Partials     1669     1671       +2     
Flag Coverage Δ
hive 39.32% <100.00%> (+<0.01%) ⬆️
mysql 58.05% <100.00%> (+<0.01%) ⬆️
postgres 58.12% <100.00%> (-0.01%) ⬇️
presto 40.90% <100.00%> (+<0.01%) ⬆️
python 59.56% <100.00%> (-0.01%) ⬇️
sqlite 57.78% <100.00%> (+<0.01%) ⬆️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread superset/security/api.py Outdated
@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. Allowing 0 as a valid dataset ID can lead to unintended global RLS rules because downstream logic treats falsy values as global. To resolve this, you can use a validate argument with marshmallow.validate.Range to ensure the dataset field only accepts positive integers.

Here is the implementation:

from marshmallow import fields, validate

class RlsRuleSchema(Schema):
    # ...
    dataset = fields.Integer(validate=validate.Range(min=1))
    clause = fields.String(required=True)

Regarding other comments on this PR, there are no additional review comments in the provided context. If you have more comments to address, please provide them, and I will be happy to help validate and implement fixes for them.

superset/security/api.py

from marshmallow import fields, validate

class RlsRuleSchema(Schema):
    # ...
    dataset = fields.Integer(validate=validate.Range(min=1))
    clause = fields.String(required=True)

A bare Integer field allowed dataset=0 (and false, coerced to 0) which
reads as falsy in get_guest_rls_filters and silently widens a scoped rule
to every dataset. Constrain dataset to strict, positive integers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bito-code-review

bito-code-review Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #9eea2c

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 89678dd..ee21f35
    • superset/security/api.py
    • tests/unit_tests/security/api_test.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Related to the REST API authentication:row-level-security Related to Row Level Security risk:breaking-change Issues or PRs that will introduce breaking changes size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants