-
Notifications
You must be signed in to change notification settings - Fork 17.6k
fix(security): Add input validation to cancel_query_id to prevent injection #36722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e9f4c21
4be051d
c2aefb7
8404cc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -204,11 +204,20 @@ def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: | |||||||
|
|
||||||||
| :param cursor: New cursor instance to the db of the query | ||||||||
| :param query: Query instance | ||||||||
| :param cancel_query_id: impala db not need | ||||||||
| :param cancel_query_id: Impala query ID in format "hex:hex" | ||||||||
| :return: True if query cancelled successfully, False otherwise | ||||||||
| """ | ||||||||
| # Validate cancel_query_id to prevent URL injection | ||||||||
| # Impala query IDs are in "hex:hex" form (16 hex chars per side) | ||||||||
| if not cls.validate_cancel_query_id( | ||||||||
| cancel_query_id, r"^[A-Fa-f0-9]{16}:[A-Fa-f0-9]{16}$" | ||||||||
| ): | ||||||||
| return False | ||||||||
|
|
||||||||
| try: | ||||||||
| impala_host = query.database.url_object.host | ||||||||
| if not impala_host: | ||||||||
| return False | ||||||||
| url = f"http://{impala_host}:25000/cancel_query?query_id={cancel_query_id}" | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The code assumes Severity Level: Minor
Suggested change
Why it matters? ⭐Verifying impala_host before building the URL avoids attempting an HTTP call to an invalid Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** superset/db_engine_specs/impala.py
**Line:** 200:200
**Comment:**
*Null Pointer: The code assumes `query.database.url_object.host` is present; if `impala_host` is None or empty the constructed URL will be invalid (e.g., "http://None:25000") and may lead to unexpected requests or errors, so check the host and return False early when missing.
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. |
||||||||
| response = requests.post(url, timeout=3) | ||||||||
| except Exception: # pylint: disable=broad-except | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -392,7 +392,13 @@ def handle_cursor(cls, cursor: Any, query: Query) -> None: | |
| def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: | ||
| with OcientEngineSpec.query_id_mapping_lock: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The code holds Severity Level: Minor |
||
| if query.id in OcientEngineSpec.query_id_mapping: | ||
| cursor.execute(f"CANCEL {OcientEngineSpec.query_id_mapping[query.id]}") | ||
| ocient_query_id = OcientEngineSpec.query_id_mapping[query.id] | ||
| # Validate query ID to prevent SQL injection (defense-in-depth) | ||
| # Ocient query IDs are alphanumeric with underscores and dashes | ||
| if not cls.validate_cancel_query_id(str(ocient_query_id), r"^[\w\-]+$"): | ||
| return False | ||
|
|
||
| cursor.execute(f"CANCEL {ocient_query_id}") | ||
| # Query has been cancelled, so we can safely remove the cursor from | ||
| # the cache | ||
| del OcientEngineSpec.query_id_mapping[query.id] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -862,6 +862,11 @@ def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: | |
| :param cancel_query_id: Postgres PID | ||
| :return: True if query cancelled successfully, False otherwise | ||
| """ | ||
| # Validate cancel_query_id to prevent SQL injection | ||
| # PostgreSQL pg_backend_pid() returns an integer | ||
| if not cls.validate_cancel_query_id(cancel_query_id, r"^\d+$"): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Severity Level: Minor |
||
| return False | ||
|
|
||
| try: | ||
| cursor.execute( | ||
| "SELECT pg_terminate_backend(pid) " # noqa: S608 | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -577,6 +577,11 @@ def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: | |||||
| :param cancel_query_id: SingleStore connection ID and aggregator ID | ||||||
| :return: True if query cancelled successfully, False otherwise | ||||||
| """ | ||||||
| # Validate cancel_query_id to prevent SQL injection | ||||||
| # SingleStore: "CONNECTION_ID AGGREGATOR_ID" (two space-separated ints) | ||||||
| if not cls.validate_cancel_query_id(cancel_query_id, r"^\d+(\s+\d+)?$"): | ||||||
| return False | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: When validation fails the method returns False silently; log a warning with the invalid Severity Level: Critical 🚨
Suggested change
Why it matters? ⭐Returning False silently on validation failure makes debugging harder. Emitting a logger.warning with the invalid value (non-sensitive) improves observability and helps operators triage issues; this is a non-invasive, useful change. Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** superset/db_engine_specs/singlestore.py
**Line:** 547:547
**Comment:**
*Possible Bug: When validation fails the method returns False silently; log a warning with the invalid `cancel_query_id` to aid debugging and alert operators rather than failing quietly.
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. |
||||||
|
|
||||||
| try: | ||||||
| cursor.execute(f"KILL CONNECTION {cancel_query_id}") | ||||||
| except Exception: # pylint: disable=broad-except | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex patterns are inconsistent in their use of anchors. Some patterns include
^and$anchors (e.g., MySQL, PostgreSQL, Redshift, Snowflake, Trino, SingleStore, Ocient) while others don't (e.g., Impala). Sincevalidate_cancel_query_idusesre.fullmatch()which implicitly anchors the pattern, the explicit anchors are redundant. For consistency and clarity, either:Recommended: Remove
^and$from all patterns since fullmatch already ensures the entire string matches.