Skip to content

Escape tokenize argument in enable_fts to prevent SQL injection - #828

Open
bunlongheng wants to merge 1 commit into
simonw:mainfrom
bunlongheng:fix/security-fts-tokenize-injection
Open

Escape tokenize argument in enable_fts to prevent SQL injection#828
bunlongheng wants to merge 1 commit into
simonw:mainfrom
bunlongheng:fix/security-fts-tokenize-injection

Conversation

@bunlongheng

@bunlongheng bunlongheng commented Aug 6, 2026

Copy link
Copy Markdown

Summary

Table.enable_fts(tokenize=...) interpolated the tokenize value directly into the CREATE VIRTUAL TABLE statement inside a single-quoted string literal:

tokenize=f"\n    tokenize='{tokenize}'," if tokenize else "",

Because the statement runs through executescript(), a tokenize value containing a single quote can close the literal and append additional statements. This is reachable from the CLI via sqlite-utils enable-fts ... --tokenize.

Fix

Route the value through the existing Database.quote() helper, which uses SQLite's own quote() to escape the string. Legitimate tokenizers such as porter (and multi-word forms like porter unicode61) are unaffected, for both FTS4 and FTS5.

Test

Added test_fts_tokenize_escaped, which confirms a crafted tokenize value cannot create an extra table. Existing tokenize tests (test_fts_tokenize) still pass.

python -m pytest tests/test_fts.py -q
# 52 passed

📚 Documentation preview 📚: https://sqlite-utils--828.org.readthedocs.build/en/828/

The tokenize value passed to Table.enable_fts() was interpolated directly
into the CREATE VIRTUAL TABLE statement inside a single-quoted string
literal. A value containing a single quote could break out of that literal
and inject arbitrary SQL, which executes via executescript(). This is
reachable from the CLI via 'enable-fts --tokenize'.

Route the value through the existing Database.quote() helper so SQLite
itself escapes it. Legitimate tokenizers such as 'porter' are unaffected.
Adds a regression test.
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.

1 participant