Skip to content

fix(mcp): Block destructive DDL (DROP, TRUNCATE, ALTER) in execute_sql#39621

Merged
alexandrusoare merged 4 commits into
masterfrom
alexandrusoare/fix/execute_sqq_handle_ddl
May 20, 2026
Merged

fix(mcp): Block destructive DDL (DROP, TRUNCATE, ALTER) in execute_sql#39621
alexandrusoare merged 4 commits into
masterfrom
alexandrusoare/fix/execute_sqq_handle_ddl

Conversation

@alexandrusoare
Copy link
Copy Markdown
Contributor

SUMMARY

Root cause:
The MCP execute_sql tool delegated all SQL validation to the executor's _check_security(), which only blocks mutations when database.allow_dml=False. When allow_dml=True, destructive DDL (DROP TABLE, TRUNCATE, ALTER) passed through unchecked — the only protection was database-level permissions. If a user had DDL privileges on the database, MCP would happily execute DROP TABLE birth_names.

Solution:
Added a fail-closed DDL pre-check in the MCP tool layer (not the executor, since SQL Lab admins may legitimately need DDL). Before the query reaches the executor:

  1. Render Jinja2 templates (if any) so templated SQL is properly validated
  2. Parse the SQL with SQLScript and check for destructive DDL nodes (exp.Dropexp.TruncateTableexp.Alter)
  3. If destructive DDL is found, return an error directing users to SQL Lab UI
  4. If parsing fails, block the query (fail-closed) rather than allowing potentially destructive SQL to bypass the check

New methods is_destructive_ddl() / has_destructive_ddl() on SQLStatement / SQLScript distinguish destructive DDL from safe DML (INSERT/UPDATE/DELETE), which is_mutating() groups together.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

TESTING INSTRUCTIONS

ADDITIONAL INFORMATION

  • 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

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.43%. Comparing base (7c4f876) to head (60e0623).
⚠️ Report is 326 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/sql_lab/tool/execute_sql.py 6.66% 14 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #39621      +/-   ##
==========================================
- Coverage   64.54%   64.43%   -0.11%     
==========================================
  Files        2565     2566       +1     
  Lines      133665   134024     +359     
  Branches    31056    31109      +53     
==========================================
+ Hits        86269    86360      +91     
- Misses      45904    46169     +265     
- Partials     1492     1495       +3     
Flag Coverage Δ
hive 39.71% <17.85%> (-0.12%) ⬇️
mysql 60.13% <17.85%> (-0.23%) ⬇️
postgres 60.21% <17.85%> (-0.23%) ⬇️
presto 41.48% <17.85%> (-0.13%) ⬇️
python 61.78% <50.00%> (-0.23%) ⬇️
sqlite 59.84% <17.85%> (-0.23%) ⬇️
unit 100.00% <100.00%> (ø)

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

☔ View full report in Codecov by Sentry.
📢 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 on lines +147 to +151
except Exception as parse_err:
await ctx.error(
"DDL pre-check failed to parse SQL, blocking query: %s"
% str(parse_err)
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if do we need to be more specific about the error here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried narrowing to SqlglotError but the disallowed-sql-import pylint rule blocks sqlglot imports outside superset/sql/.

Comment thread tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py Outdated
@alexandrusoare alexandrusoare marked this pull request as ready for review April 27, 2026 10:35
@alexandrusoare alexandrusoare requested a review from msyavuz April 27, 2026 10:36
@dosubot dosubot Bot added change:backend Requires changing the backend sqllab Namespace | Anything related to the SQL Lab labels Apr 27, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 27, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit ddda3b7
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/69ef3bd4cc01830008b2a82a
😎 Deploy Preview https://deploy-preview-39621--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 27, 2026

Code Review Agent Run #855e40

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/sql_lab/tool/execute_sql.py - 1
    • Misleading error message · Line 155-157
      The error message implies the SQL has syntax errors, but the failure occurs during security validation parsing. This can mislead users into thinking their SQL is invalid when it's actually a parser limitation. Update the message to clarify the issue is with security validation.
Review Details
  • Files reviewed - 4 · Commit Range: 08dc097..ddda3b7
    • superset/mcp_service/sql_lab/tool/execute_sql.py
    • superset/sql/parse.py
    • tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
    • tests/unit_tests/sql/parse_tests.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

Comment thread superset/sql/parse.py Outdated
Copy link
Copy Markdown
Contributor

@EnxDev EnxDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

"""Tests for destructive DDL blocking in execute_sql."""

@pytest.fixture
def ddl_mocks(self):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add explicit type annotations to the fixture method parameters and return type so the new test fixture follows the typing rule for newly added functions. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The newly added fixture method is unannotated: self has no type and the function has no return type annotation. This matches the typing rule violation described by the suggestion.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
**Line:** 1227:1227
**Comment:**
	*Custom Rule: Add explicit type annotations to the fixture method parameters and return type so the new test fixture follows the typing rule for newly added functions.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

yield mock_database

@pytest.mark.asyncio
async def test_drop_table_blocked(self, ddl_mocks, mcp_server):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add explicit type hints for all parameters and the return type on this newly added async test method. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

This added async test method has no type annotations for its parameters and no return type annotation. The suggestion correctly identifies a real typing omission in the new code.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
**Line:** 1241:1241
**Comment:**
	*Custom Rule: Add explicit type hints for all parameters and the return type on this newly added async test method.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

ddl_mocks.execute.assert_not_called()

@pytest.mark.asyncio
async def test_truncate_blocked(self, ddl_mocks, mcp_server):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Annotate this new async test method with explicit parameter types and a return type to satisfy the typing requirement. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The test method is newly introduced and untyped, with no parameter annotations and no return annotation. This is a genuine match for the stated typing requirement.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
**Line:** 1255:1255
**Comment:**
	*Custom Rule: Annotate this new async test method with explicit parameter types and a return type to satisfy the typing requirement.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

ddl_mocks.execute.assert_not_called()

@pytest.mark.asyncio
async def test_alter_table_blocked(self, ddl_mocks, mcp_server):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add type annotations for each argument and the return type on this newly introduced async method. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

This new async test function lacks both parameter type hints and a return type. The suggestion is therefore addressing a real violation of the typing rule.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
**Line:** 1268:1268
**Comment:**
	*Custom Rule: Add type annotations for each argument and the return type on this newly introduced async method.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

ddl_mocks.execute.assert_not_called()

@pytest.mark.asyncio
async def test_drop_in_multi_statement_blocked(self, ddl_mocks, mcp_server):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Update this new async test method to include explicit parameter type hints and an annotated return type. [custom_rule]

Severity Level: Minor ⚠️

Why it matters? 🤔

The method is newly added and untyped, with no annotations on its parameters or return value. This is a valid typing-related issue under the stated rule.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/sql_lab/tool/test_execute_sql.py
**Line:** 1286:1286
**Comment:**
	*Custom Rule: Update this new async test method to include explicit parameter type hints and an annotated return type.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 28, 2026

Code Review Agent Run #a60d28

Actionable Suggestions - 0
Review Details
  • Files reviewed - 3 · Commit Range: ddda3b7..60e0623
    • superset/mcp_service/sql_lab/tool/execute_sql.py
    • superset/sql/parse.py
    • tests/unit_tests/sql/parse_tests.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

@EnxDev EnxDev added the hold:testing! On hold for testing label Apr 29, 2026
@alexandrusoare alexandrusoare merged commit b98bd2a into master May 20, 2026
66 of 67 checks passed
@alexandrusoare alexandrusoare deleted the alexandrusoare/fix/execute_sqq_handle_ddl branch May 20, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend hold:testing! On hold for testing size/L sqllab Namespace | Anything related to the SQL Lab

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants