Skip to content

chore(security): suppress validated false positives in code scanning#541

Merged
ericfitz merged 3 commits into
mainfrom
chore/code-scanning-triage
Jul 16, 2026
Merged

chore(security): suppress validated false positives in code scanning#541
ericfitz merged 3 commits into
mainfrom
chore/code-scanning-triage

Conversation

@ericfitz

@ericfitz ericfitz commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

Full triage of all 63 open GitHub code scanning alerts (CodeQL + gosec) — every alert was validated against the actual code. Zero true positives in shipped code. This PR makes the suppressions durable so validated false positives stop reappearing in the Security tab, and closes the one latent gap the triage surfaced (#540):

  • gosec annotations (14 sites, comment-only changes): convert //nolint:gosec to // #nosec GXXX -- <justification>. Standalone gosec (the CI SARIF job) ignores //nolint and only honors #nosec — which is why already-justified findings kept resurfacing. golangci-lint's gosec honors #nosec too (verified: make lint → 0 issues), so local lint coverage is unchanged.
  • gosec CI job: add -exclude-dir=test -exclude-dir=wstest. Both are separate Go modules never compiled into the server binary; this keeps the Security tab scoped to shipped code and closes the 14 test-harness alerts on the next upload.
  • CodeQL config: path-ignore .tmi-clients/** (CI checkout of the generated client repo — its Debug-gated httputil.DumpRequestOut is stock OpenAPI-generator template code) and refresh the known-FP documentation for GORM map-based queries with the validated safe sub-patterns (ColumnMap/OrderByCol literal keys, static-SQL clause.Expr), plus a new note on the slogging clear-text-logging sink FPs.
  • New guardrail (fixes chore: harden log redaction against format-string secret interpolation #540): scripts/check-sensitive-log-args.py fails the build when a sensitive config/credential field (Password, LLMAPIKey, ClientSecret, …) is passed to a logger call — attribute-based redaction cannot catch format-string interpolation. Multi-line-call aware, string-literal stripped, len(x.Secret) allowed as a safe derived value. Wired into make lint and the CI lint job.

Triage results

Group Alerts Verdict
CodeQL go/sql-injection 19 FP — GORM map-Where, hardcoded column keys, parameterized values (dismissed)
CodeQL go/clear-text-logging (TMI code) 13 FP — generic slogging sinks / key names only (dismissed)
CodeQL go/weak-sensitive-data-hashing 1 FP — SHA256 wiring fingerprint, not password storage (dismissed)
CodeQL clear-text-logging (.tmi-clients) 2 Won't fix — third-party generated, Debug-gated; path-ignored going forward
gosec main code (G101/G115/G304/G306) 14 FP/accepted — operator-controlled paths, name constants, benign conversions; auto-close via #nosec
gosec test code (G102/G104/G107/G112/G404) 14 Test-only modules, never shipped; auto-close via -exclude-dir

Verification

  • make lint — 0 issues, including the new check (confirms golangci-lint gosec honors the #nosec form)
  • New checker negative-tested: injected logger.Info("key=%s", cfg.LLMAPIKey) + a multi-line violation → both detected; removed → clean
  • make build-server — pass
  • make test-unit — 24 packages passed, 0 failed
  • security-regression scan — VERDICT: PASS (all pinning tests present, no dangerous patterns in diff)

Fixes #540

🤖 Generated with Claude Code

https://claude.ai/code/session_014VXEwai1f6hYn1Kd7BHepL

Full triage of all 63 open GitHub code scanning alerts (CodeQL + gosec)
found zero true positives in shipped code. This change makes the
suppressions durable:

- Convert //nolint:gosec annotations to #nosec GXXX form at 14 sites:
  standalone gosec (the CI SARIF job) ignores //nolint and only honors
  #nosec, which is why already-justified findings kept reappearing in
  the Security tab. golangci-lint's gosec honors #nosec too, so lint
  coverage is unchanged.
- gosec CI job: exclude test/ and wstest/ (separate Go modules, never
  compiled into the server binary) so the Security tab stays scoped to
  shipped code.
- CodeQL: path-ignore .tmi-clients/** (CI checkout of the generated
  client repo; its Debug-gated request dump is third-party generated
  code) and refresh the known-FP documentation for GORM map-based
  queries with the validated safe sub-patterns (ColumnMap/OrderByCol
  literal keys, static-SQL clause.Expr) plus a new note on the slogging
  clear-text-logging sink FPs.

The 33 CodeQL false-positive alerts are being dismissed in GitHub with
per-group justifications. Hardening follow-up for the attribute-only
log-redaction gap is tracked in #540.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014VXEwai1f6hYn1Kd7BHepL
Comment thread cmd/genconfig/main.go Fixed
Comment thread cmd/genconfigdocs/main.go Fixed
Comment thread pkg/extract/ooxml_common.go Fixed
Comment thread pkg/extract/ooxml_common.go Fixed
ericfitz added 2 commits July 15, 2026 22:42
Log redaction in internal/slogging is attribute-based: redactionHandler
matches slog.Attr keys and SanitizeLogMessage only strips control
characters, so a secret interpolated directly into a format string
(e.g. logger.Info("key=%s", cfg.LLMAPIKey)) would bypass redaction.

Add scripts/check-sensitive-log-args.py: scans non-test Go files under
api/, auth/, cmd/, internal/, and pkg/ for logger-style calls whose
argument span (multi-line aware, string-literal stripped) references a
sensitive config/credential field (Password, LLMAPIKey, ClientSecret,
etc.). len(x.Secret) is allowed as a safe derived value. Wired into
make lint (new check-sensitive-log-args target) and the Security &
Quality CI lint job.

Fixes #540
gosec associates an end-of-line comment on an `if ... {` line with the
block contents, not the if node where the violation is reported, so the
4 directives placed after `{` (G306 in genconfig/genconfigdocs, G115 in
ooxml_common) did not suppress and resurfaced as new alerts on the PR.
Directives on plain statements attach correctly and were unaffected.
Verified with standalone gosec v2.22.5 using the exact CI invocation:
0 issues repo-wide.
@ericfitz
ericfitz merged commit d3f5683 into main Jul 16, 2026
12 checks passed
@ericfitz
ericfitz deleted the chore/code-scanning-triage branch July 16, 2026 03:09
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.

chore: harden log redaction against format-string secret interpolation

2 participants