Skip to content

fix(sqlalchemy-spanner): prevent SQL injection via JSON key indexing - #18982

Merged
parthea merged 3 commits into
mainfrom
sqlAlchemy-vlnrFix
Nov 4, 2026
Merged

parthea merged 3 commits into
mainfrom
sqlAlchemy-vlnrFix

Conversation

@sinhasubham

@sinhasubham sinhasubham commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

Fixes b/573632295 a SQL injection vulnerability in SpannerSQLCompiler._generate_generic_binary where subscript JSON keys were directly concatenated into JSON_VALUE(...) SQL strings without parameterization or escaping.

Testing:

Add unit and MockServer test coverage for SQL injection prevention, boundary keys, nested paths, and statement caching.

Fixes a SQL injection vulnerability in SpannerSQLCompiler._generate_generic_binary
where subscript JSON keys were directly concatenated into JSON_VALUE(...) SQL strings
without parameterization or escaping.

- Introduce SpannerJSONIndexType and SpannerJSONPathType registered in
  SpannerDialect.colspecs for types.JSON.JSONIndexType and types.JSON.JSONPathType.
- Route visit_json_getitem_op_binary, visit_json_path_getitem_op_binary, and
  _generate_generic_binary through _json_value_binary to parameterize JSONPath
  lookups by default, resolving SQL injection and statement cache collisions.
- Add _escape_json_path_key conforming to GoogleSQL kEscKeyLexerStandard rules and
  _escape_spanner_string_literal for safe literal rendering.
- Harden SpannerSQLCompiler.render_literal_value against raw triple-quote breakouts,
  control characters, and format placeholder mismatches.
- Add comprehensive unit and MockServer test coverage for SQL injection prevention,
  boundary keys (0, True/False, empty strings, quotes, backslashes), nested paths,
  and statement caching.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces robust JSONPath and JSON index escaping and formatting for the Google Cloud Spanner SQLAlchemy dialect, addressing potential SQL injection vulnerabilities during JSON querying. It adds custom types SpannerJSONIndexType and SpannerJSONPathType along with utility functions to safely format and escape JSON keys and paths. The feedback suggests using \g<1> instead of \1 in re.sub to prevent parsing ambiguity, and calling super().bind_processor(dialect) instead of the internal self.string_bind_processor(dialect) to avoid relying on SQLAlchemy's internal implementation details.

@sinhasubham
sinhasubham marked this pull request as ready for review November 4, 2026 09:25
@sinhasubham
sinhasubham requested a review from a team as a code owner November 4, 2026 09:25
@parthea parthea self-assigned this Nov 4, 2026
@parthea
parthea merged commit c0dba72 into main Nov 4, 2026
56 checks passed
@parthea
parthea deleted the sqlAlchemy-vlnrFix branch November 4, 2026 20:15
parthea pushed a commit that referenced this pull request Nov 12, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.21.0](sqlalchemy-spanner-v1.20.1...sqlalchemy-spanner-v1.21.0)
(2026-11-12)


### Features

* declare support for Python 3.15
([#18737](#18737))
([65c8767](65c8767))
* **sqlalchemy-spanner:** wire timeout execution option through to DBAPI
Cursor.timeout
([#18485](#18485))
([1de2e3f](1de2e3f))


### Bug Fixes

* repair broken and stale repository URLs in package metadata
([#18498](#18498))
([54dbd12](54dbd12)),
refs
[#18497](#18497)
* **spanner-sqlalchemy:** add WHERE 1=1 to unqualified DELETE and UPDATE
([#19024](#19024))
([5a2b34e](5a2b34e))
* **sqlalchemy-spanner:** isolate literal round trip test tables with
unique naming and teardown
([#18623](#18623))
([75cdf3b](75cdf3b))
* **sqlalchemy-spanner:** prevent SQL injection via JSON key indexing
([#18982](#18982))
([c0dba72](c0dba72))
* **sqlalchemy-spanner:** resolve compliance and migration failures with
Alembic 1.20 and SQLAlchemy 2.1
([#18570](#18570))
([873ef99](873ef99))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants