🛡️ Sentinel: [CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query#115
🛡️ Sentinel: [CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query#115mattjoyce wants to merge 1 commit into
Conversation
… query 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, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
📝 WalkthroughWalkthroughThis PR fixes a SQL injection vulnerability in the SQLite backend by replacing unsafe string interpolation with parameterized queries when checking table column metadata. The code change and its security rationale are documented in the project sentinel log. ChangesSQL injection vulnerability fix
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review Summary by QodoFix SQL injection in SQLite PRAGMA table_info query
WalkthroughsDescription• Fix critical SQL injection vulnerability in sqliteColumnExists function • Replace unsafe fmt.Sprintf string interpolation with parameterized query • Use SQLite's pragma_table_info(?) table-valued function for safe parameterization • Document vulnerability and prevention strategy in .jules/sentinel.md Diagramflowchart LR
A["Unsafe fmt.Sprintf<br/>PRAGMA table_info(%s)"] -->|"Replace with"| B["Parameterized query<br/>pragma_table_info(?)"]
B -->|"Result"| C["SQL injection prevention<br/>Safe table name handling"]
File Changes1. internal/storage/sqlite.go
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
46 rules 1. Missing injection regression test
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ductile | c387b56 | Commit Preview URL Branch Preview URL |
Jun 05 2026, 11:45 AM |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.jules/sentinel.md (1)
1-5:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix heading structure to satisfy markdownlint checks.
Current layout triggers MD041 and MD022 (
H1 first lineandblank line around heading). This can block lint-gated merges.Suggested patch
-## 2025-02-28 - [CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query +# Sentinel security learnings + +## 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.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.jules/sentinel.md around lines 1 - 5, The top-level heading in the sentinel entry ("2025-02-28 - [CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query") must be formatted as an H1 and be preceded and followed by a blank line to satisfy markdownlint rules MD041 and MD022; update the heading so it begins with a single "# " on its own line, ensure there is an empty line above it (or make it the very first line) and add a single blank line after the heading before the body text, keeping the existing heading text and details intact.internal/storage/sqlite.go (1)
203-227: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winWrap
sqliteColumnExistspropagated errors with operation context.This function now handles a security-sensitive metadata path, but it still returns raw driver errors. Add table-scoped context on query/scan/iteration failures.
Suggested patch
func sqliteColumnExists(ctx context.Context, db *sql.DB, table, column string) (bool, error) { cols, err := db.QueryContext(ctx, "SELECT cid, name, type, \"notnull\", dflt_value, pk FROM pragma_table_info(?)", table) if err != nil { - return false, err + return false, fmt.Errorf("query pragma_table_info for table %q: %w", table, err) } defer func() { _ = cols.Close() }() @@ if err := cols.Scan(&cid, &name, &typ, ¬null, &dfltValue, &pk); err != nil { - return false, err + return false, fmt.Errorf("scan pragma_table_info row for table %q: %w", table, err) } @@ if err := cols.Err(); err != nil { - return false, err + return false, fmt.Errorf("iterate pragma_table_info rows for table %q: %w", table, err) } return false, nil }As per coding guidelines, "Wrap propagated errors with useful context".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/storage/sqlite.go` around lines 203 - 227, sqliteColumnExists currently returns raw driver errors; wrap errors from db.QueryContext, the cols.Scan call and the cols.Err() check with contextual messages that include the table and column names. Update the db.QueryContext error handling to return fmt.Errorf("sqliteColumnExists: query pragma_table_info for table %q failed: %w", table, err), wrap the cols.Scan error as fmt.Errorf("sqliteColumnExists: scanning pragma_table_info for table %q column %q failed: %w", table, column, err), and wrap the cols.Err() result similarly (e.g. "iterating pragma_table_info for table %q failed: %w"), so callers of sqliteColumnExists receive table-scoped context for all propagated errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In @.jules/sentinel.md:
- Around line 1-5: The top-level heading in the sentinel entry ("2025-02-28 -
[CRITICAL] Fix SQL injection in SQLite PRAGMA table_info query") must be
formatted as an H1 and be preceded and followed by a blank line to satisfy
markdownlint rules MD041 and MD022; update the heading so it begins with a
single "# " on its own line, ensure there is an empty line above it (or make it
the very first line) and add a single blank line after the heading before the
body text, keeping the existing heading text and details intact.
In `@internal/storage/sqlite.go`:
- Around line 203-227: sqliteColumnExists currently returns raw driver errors;
wrap errors from db.QueryContext, the cols.Scan call and the cols.Err() check
with contextual messages that include the table and column names. Update the
db.QueryContext error handling to return fmt.Errorf("sqliteColumnExists: query
pragma_table_info for table %q failed: %w", table, err), wrap the cols.Scan
error as fmt.Errorf("sqliteColumnExists: scanning pragma_table_info for table %q
column %q failed: %w", table, column, err), and wrap the cols.Err() result
similarly (e.g. "iterating pragma_table_info for table %q failed: %w"), so
callers of sqliteColumnExists receive table-scoped context for all propagated
errors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8c166b7d-01ff-416c-878b-561f1b576e49
📒 Files selected for processing (2)
.jules/sentinel.mdinternal/storage/sqlite.go
🚨 Severity: CRITICAL
💡 Vulnerability: The
sqliteColumnExistsfunction dynamically interpolates thetableargument usingfmt.Sprintfdirectly into aPRAGMA table_info(%s)string query. This risks SQL injection if any user or dynamically generated string input is supplied as the table name.🎯 Impact: This allows an attacker to inject arbitrary SQL logic, bypass security configurations, or alter data if the table input were manipulated.
🔧 Fix: Adopted parameterization through SQLite's built-in
pragma_table_info(?)table-valued function.✅ Verification: Ran
go test -v ./internal/storage/...to verify proper validation without SQL injection risks.PR created automatically by Jules for task 4209861840213903478 started by @mattjoyce
Summary by CodeRabbit