Skip to content

fix(go): stop SQLi false positives on constant/parameterized queries - #248

Merged
jaurakunal merged 1 commit into
mainfrom
fix/go-sqli-query-collision
Sep 22, 2026
Merged

jaurakunal merged 1 commit into
mainfrom
fix/go-sqli-query-collision

Conversation

@jaurakunal

Copy link
Copy Markdown
Owner

What

An adversarial precision pass — running our Go pack over AWS deception-bench's code-level samples — exposed 6 false positives: our SQLi taint rule fired on constant, no-user-input queries like db.Query("SELECT id FROM users LIMIT 50").

Root cause

The Gin source pattern $C.Query(...) (for c.Query("param")) also matched database/sql's db.Query(...) — so every constant DB query was read as both a taint source and the sink, self-flowed, and false-positived. (It also means govwa's SQLi was being "caught" by this collision, not real dataflow.)

Fix

  • Drop $C.Query(...) from the shared request sources; Gin still covered by DefaultQuery/Param/PostForm/etc.
  • Redesign the SQLi taint rule around the real dynamic-build signal: source = fmt.Sprintf/concatenation, sink = single-arg query (gosec G201). Constant → no source → not flagged; parameterized → multi-arg → excluded; Sprintf/concat-built (inline or assign-then-execute, e.g. govwa) → still caught.
  • Inline the shared source list (semgrep's YAML-anchor handling was fragile).

Verified

  • deception-bench Go SQLi FPs: 6 → 0; constant/parameterized no longer flagged, dynamic-built still caught.
  • govwa SQLi still caught; go-sast 4/4; SAST-injection fixture gate 53/53, 0 FP; full suite 2621 passed.
  • Mined the exact FP class (a bare constant query) into safe/ as a permanent regression guard.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EZ4QoTqRoYWE25CNoV2Wfy

An adversarial precision pass (running our Go pack over AWS deception-bench's
code-level samples) exposed 6 false positives: our SQLi taint rule fired on
constant, no-user-input queries like `db.Query("SELECT id FROM users LIMIT 50")`.

Root cause: the Gin source pattern `$C.Query(...)` (for `c.Query("param")`) also
matched database/sql's own `db.Query(...)` — so every constant DB query was read
as BOTH a taint source and the sink, self-flowed, and false-positived. (It also
means govwa's SQLi was being "caught" by this collision, not real dataflow.)

Fix:
- Drop `$C.Query(...)` from the shared request sources (it collides with
  db.Query/stmt.Query); Gin still covered by DefaultQuery/Param/PostForm/etc.
- Redesign the SQLi taint rule to key on the real dynamic-build signal —
  source = fmt.Sprintf/concatenation, sink = single-arg query (gosec G201). A
  constant query has no source and is never flagged; a parameterized call is
  multi-arg and excluded by the sink; a Sprintf/concat-built query (inline or
  assign-then-execute, e.g. govwa) is still caught.
- Inline the shared source list (semgrep's YAML-anchor handling was fragile).

Verified:
- deception-bench Go SQLi FPs: 6 -> 0. Constant/parameterized queries no longer
  flagged; Sprintf/concat-built queries still are.
- govwa SQLi still caught; go-sast still 4/4; SAST-injection fixture gate still
  53/53, 0 FP. Full suite: 2621 passed.
- Mined the exact FP class (a bare constant query) into the safe/ fixtures as a
  permanent regression guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ4QoTqRoYWE25CNoV2Wfy
@jaurakunal
jaurakunal merged commit 180d2e1 into main Sep 22, 2026
8 checks passed
@jaurakunal
jaurakunal deleted the fix/go-sqli-query-collision branch September 22, 2026 13:07
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