Skip to content

SAST — Static Application Security Testing

Statement

ClaimGuard runs Snyk Code as the static analysis tool over its TypeScript/JavaScript and Python codebases. Every Snyk Code finding is either fixed in source or formally deferred in .snyk with a per-finding justification that names the code-level invariant the analyzer missed.

Implementation

Tooling

  • Engine: Snyk Code.
  • Languages covered: Node.js / TypeScript (server/, src/, functions/), Python (tools/).
  • Last full scan: 2026-04-22 (the engagement that produced the Snyk summary).

What Snyk Code flagged and how it was disposed

Snyk Code findings fall into two categories:

  1. Real findings — fixed in source. Examples on this codebase:
  2. SQL injection in claims/admin queries → parameterized queries throughout (P0-02-sql-injection.md).
  3. DOM XSS in a React render path → React Router 6.30.x bump (P2-02-dom-xss.md).
  4. Path traversal in upload + internal handlers → safePath and safe_path.py containment helpers, applied at every entry point (P1-02-path-traversal-http.md, P2-05-path-traversal-internal.md).
  5. DOM open redirect in the React Router shell (P2-03-open-redirect.md).

  6. False positives — kept in source as documented invariants, with a .snyk entry that names what the analyzer missed:

  7. UUID gates the analyzer treats as untrusted input even though the value passed a strict regex check.
  8. Whitelisted column names in dynamic SQL — the analyzer flags the dynamic concat; the actual code only accepts values from a hardcoded allowlist.
  9. Path containment helpers (safePath, isInside) the analyzer can't follow through a function boundary.
  10. Service-layer safeFetch wraps — an outbound fetch reached through the keystone but flagged on the inner call site.
  11. localStorage KEY-name reads the analyzer treats as PII reads when the code is reading the name of a key, not its value.

Every false-positive entry in .snyk carries a reason: field that names the specific guard the analyzer missed. None are blanket suppressions.

Reachability and flow-confirmation

For severity-tier findings (P0/P1), each finding has an attached note in docs/security/findings/ that walks the actual call path — not just the analyzer's reported flow — and confirms the input source and sink. This keeps the team honest about whether a fix is at the right layer (e.g., fixing at the route guard vs. at the database driver).

Engineering invariants enforced via SAST

The findings exercise has produced a set of invariants documented in docs/security/README.md that future SAST runs are expected to keep clean:

  • All outbound HTTP routes through server/src/lib/safeFetch.js.
  • All filesystem path joins go through safePath (server/) or safe_path.py (tools/).
  • All dynamic SQL goes through parameterized queries; column-name selection uses an allowlist.

When a Snyk Code finding contradicts one of these invariants, the fix is in source — not in .snyk.

Status

implemented — verified 2026-04-26.

The 2026-04-22 Snyk Code findings were either fixed in source or formally deferred. The .snyk policy file is the authoritative record; all deferrals expire 2027-04-22 and are scheduled for annual review.

Roadmap

  • CI integration — run snyk code test on every PR with branch protection blocking new high-severity findings.
  • PR comment integration — surface SAST findings inline so reviewers see them without leaving the PR.

Known SAST tooling caveats

  • snyk code test does not machine-apply .snyk ignores via the CLI for Snyk Code rules; entries under javascript/* and python/* rule keys are for the Snyk web UI / documentation. Locally, the CLI will still report deferred findings — engineers must cross-reference .snyk.
  • Snyk's CLI walks node_modules/.cache and similar agent-side temp directories by default. Internal scan jobs filter .claude/worktrees/* from output to avoid double-counting findings from stale agent worktrees.