From c387b5660f43e0b7a77aec85c14d26853091e542 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 11:44:44 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20SQL=20injection=20in=20SQLite=20PRAGMA=20table=5Finfo?= =?UTF-8?q?=20query?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes a critical SQL injection vulnerability in `internal/storage/sqlite.go` where `sqliteColumnExists` was vulnerable due to the dynamic string interpolation of a table name into a `PRAGMA table_info(%s)` query using `fmt.Sprintf()`. To resolve this issue, the function now safely utilizes SQLite's table-valued function `pragma_table_info(?)`, allowing parameterization and thereby preventing SQL injection. We also added an entry to `.jules/sentinel.md` documenting this finding and learning. Co-authored-by: mattjoyce <278869+mattjoyce@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ internal/storage/sqlite.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..73545156 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-02-28 - [CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query +**Vulnerability:** The `sqliteColumnExists` function in `internal/storage/sqlite.go` was vulnerable to SQL injection because it used `fmt.Sprintf` to directly interpolate a table name into a `PRAGMA table_info(%s)` string query. +**Learning:** PRAGMA statements cannot accept parameterized inputs natively. If user input reaches this function, an attacker could terminate the string and inject arbitrary SQL. +**Prevention:** Instead of string formatting with `PRAGMA table_info`, always use SQLite's table-valued function `pragma_table_info(?)` which safely supports query parameterization (`SELECT ... FROM pragma_table_info(?)`). Note that when doing this, columns like `notnull` must be escaped with double quotes (e.g., `"notnull"`) as they are reserved SQL keywords. diff --git a/internal/storage/sqlite.go b/internal/storage/sqlite.go index 8c0cb1ed..8c4ff20b 100644 --- a/internal/storage/sqlite.go +++ b/internal/storage/sqlite.go @@ -200,7 +200,7 @@ LIMIT 1; } func sqliteColumnExists(ctx context.Context, db *sql.DB, table, column string) (bool, error) { - cols, err := db.QueryContext(ctx, fmt.Sprintf("PRAGMA table_info(%s);", table)) + cols, err := db.QueryContext(ctx, "SELECT cid, name, type, \"notnull\", dflt_value, pk FROM pragma_table_info(?)", table) if err != nil { return false, err }