diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..d5f81d3 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-05-24 - [SQL Injection via String Formatting in PRAGMA table_info] +**Vulnerability:** Found a SQL injection risk in `internal/storage/sqlite.go` where `fmt.Sprintf("PRAGMA table_info(%s);", table)` was used to dynamically construct a schema inspection query. +**Learning:** SQLite `PRAGMA` statements historically do not support parameterization. This led to using string concatenation or `fmt.Sprintf` to build the query dynamically. +**Prevention:** Use SQLite's parameterizable table-valued functions instead. For `PRAGMA table_info`, the equivalent parameterized query is `SELECT cid, name, type, "notnull", dflt_value, pk FROM pragma_table_info(?)`. Ensure to double quote `"notnull"` as it's a reserved keyword. diff --git a/internal/storage/sqlite.go b/internal/storage/sqlite.go index 8c0cb1e..727c49d 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 }