Skip to content

v2.86.0: fallow security candidate catalogue + JSON kind discriminator

Choose a tag to compare

@BartWaardenburg BartWaardenburg released this 02 Jun 11:02
· 301 commits to main since this release
v2.86.0
1c8319d

Highlights

fallow security: a local security-candidate layer for agent verification

fallow security is an opt-in command that surfaces local, deterministic security candidates (not verified vulnerabilities) for a human or coding agent to verify. fallow ships the signal; your agent confirms and fixes.

This release expands it from one rule to a data-driven catalogue spanning 9 CWE categories:

  • dangerous HTML (CWE-79), OS command injection (CWE-78), code injection (CWE-94), SQL injection (CWE-89), SSRF (CWE-918), path traversal (CWE-22), open redirect (CWE-601), runtime-selectable crypto algorithm (CWE-327), unsafe deserialization (CWE-502)
  • Plus the original client-server-leak rule: a "use client" file that transitively reaches a non-public process.env secret, with a structural import-hop trace.

Design choices that keep the signal honest:

  • Conservative by default. A candidate fires only when the relevant argument is non-literal; a fully literal value (el.innerHTML = "<b>x</b>", child_process.exec("ls")) is never flagged. fallow prefers false-negatives over false-positives.
  • Parameterized SQL is not flagged. Tagged-template sql`${x}` and the object form .execute({ sql, args }) bind safely and do not fire; only string concatenation, interpolated template literals into .query() / .execute(), and sql.raw(...) do.
  • Node sinks are provenance-gated to their import source (command injection to node:child_process, vm code injection to node:vm, path traversal to node:path, crypto to node:crypto, deserialization to js-yaml / node-serialize).
  • Build configs and test files are excluded from candidate generation.
  • Opt-in and isolated. The rules default to off, never appear under bare fallow or the audit gate, and fallow security is the only surface. Output is human, JSON, or SARIF (SARIF emits at note level with per-category rule IDs and CWE tags for the GitHub Security tab).
  • Blind spots are counted in-band, so an empty result with a non-zero unresolved count is never a clean bill.

Adding a CWE category is a single catalogue entry with no code churn. Scope which categories run with security.categories include / exclude lists, and suppress a file with // fallow-ignore-file security-sink.

Changed

  • JSON envelope outputs now carry a top-level kind discriminator (dead-code, health, dupes, combined, audit, security, ...), so consumers identify the shape by kind instead of field-presence heuristics. schema_version is bumped; --legacy-envelope keeps the previous root shape for one migration cycle. (Closes #413.)

Fixed

Detection and integration fixes across this cycle:

  • A bare "@" plugin alias no longer swallows @scope/* npm packages (#838).
  • declare ambient class properties are no longer reported as unused class members (#839).
  • new URL('./dir', import.meta.url) directory targets no longer surface as unresolved imports (#840).
  • Quoted globs in package.json scripts are registered as entry points (#841).
  • NestJS lifecycle and handler methods are credited as used (#843).
  • A method called on an instanceof-narrowed value is credited as a use of that class's member (#845).
  • Oxlint config packages referenced through extends are credited (#846).
  • Bun bunfig.toml preload files are tracked, and the Bun plugin activates on @types/bun (#847).
  • duplicate-export no longer over-reports across unrelated packages (#848).
  • Pinia stores auto-imported by @pinia/nuxt are tracked (#740).
  • Nuxt composables and utils referenced only through auto-imports are tracked (#739).
  • resolve.alias shared via an imported identifier or built with spreads is no longer ignored. Thanks @michaljuris for the report (#811).
  • Svelte markup <script src> tags no longer surface as unresolved imports. Thanks @codingthat for the report (#835).
  • The GitHub Action now uploads SARIF on public repositories. Thanks @cloud-walker for the detailed report (#817).
  • The GitHub Action no longer logs a spurious SARIF generation failed warning on repos with issues (#813).
  • Two built-in plugins sharing a config file no longer emit an un-actionable collision warning (#808).
  • fallow health surfaces CRAP coverage-source consistency in JSON and adds a tunable secondary refactor band (#474).

Full Changelog: v2.85.0...v2.86.0