Skip to content

Commit f687060

Browse files
authored
fix(pandas-gbq): reject backticks in parse_table_id (#18156)
parse_table_id validates the table id but its regex only excludes "." and ":" at certain positions, so a backtick passes through into the parts that core/biglake.py and core/sample.py interpolate into a backtick-quoted FROM `...` and run via bqclient.query. A backtick closes the identifier quoting and lets the remainder of the id run as SQL, and the public sample() entry point routes every table id through this one helper, so an id like `p.c.n.t` ORDER BY (SELECT 1) --` reaches the query. Reject backticks in parse_table_id where the id is already validated; valid project/dataset/table names can't contain one, so legitimate ids are unchanged. - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/google-cloud-python/issues) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [x] Ensure the tests and linter pass - [x] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary)
1 parent dfb0e36 commit f687060

2 files changed

Lines changed: 13 additions & 0 deletions

File tree

packages/pandas-gbq/pandas_gbq/core/resource_references.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ def parse_table_id(table_id: str) -> Union[BigLakeTableId, BigQueryTableId]:
5353
if any(part == "" for part in inner_parts):
5454
raise ValueError(f"Invalid table ID: {table_id}")
5555

56+
# The parsed parts are interpolated into backtick-quoted table references in
57+
# generated SQL (see core/biglake.py and core/sample.py). A backtick can't
58+
# appear in a real project/dataset/table name, and one here would close the
59+
# identifier quoting and let the rest of the string run as SQL, so reject it
60+
# while we're validating the table ID rather than downstream.
61+
if "`" in table_id:
62+
raise ValueError(f"Invalid table ID: {table_id}")
63+
5664
if len(inner_parts) == 1:
5765
return BigQueryTableId(
5866
project_id=regex_match.group("project"),

packages/pandas-gbq/tests/unit/core/test_core_resource_references.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ def test_parse_table_id_valid(table_id, expected):
6767
".my_dataset.my_table",
6868
"my-project.my_dataset.",
6969
"my-project..my_table",
70+
# A backtick would close the identifier quoting in the generated SQL and
71+
# let the rest of the string run as SQL, so it must be rejected here.
72+
"my-project.my_dataset.my_table` ORDER BY (SELECT 1) -- ",
73+
"my-project.my_catalog.my_namespace.evil` UNION ALL SELECT 1 -- ",
74+
"my-project.my_dataset.`",
7075
],
7176
)
7277
def test_parse_table_id_invalid(table_id):

0 commit comments

Comments
 (0)