foxguard: The Rust Security Scanner That Wants to Feel Like a Linter

A local-first tool with AST parsing, cross-file taint tracking, secret detection, and PQC compliance, built to give developers security feedback before they leave the editor.

8 min read • View on GitHub • More from PwnKit-Labs

A developer desk in wide view with a terminal stream on one side and a compact scanning instrument on the other. Code files feed into the tool like a tidy pipeline, while a heavy security gate sits unused in the background. It explains that foxguard treats security analysis as a local habit instead of a distant checkpoint.
foxguard reframes security scanning as something that belongs in the inner loop, not just in CI.
Key Takeaways

foxguard is interesting because it does not ask developers to change where they work. It tries to make security analysis feel like linting: local, immediate, and boring in the best way. The premise is simple. If a scanner is fast enough and useful enough to run while you are still editing, it stops being a gate and starts being part of the workflow.

Security analysis that behaves like linting

Most security scanners live too far away from the code. They are accurate enough to matter, but slow enough that people only check the results after a branch is already noisy. foxguard pushes in the opposite direction. It is built around local runs, pre-commit hooks, and changed-file scans, which is a subtle but important product choice: feedback lands while the developer still has context.

That changes how the tool feels. Instead of a central review system, foxguard behaves more like a utility sitting next to formatters and linters. The project’s README puts the problem plainly: “So developers don't run them locally — they get pushed to CI, findings pile up in PRs, and nobody looks at them.” The point is not just speed. The point is keeping the scan close enough to the work that it actually gets used.

Why foxguard is not just a faster Semgrep

foxguard is not only a rule runner. It blends several layers: built-in Rust rules, tree-sitter AST parsing, taint tracking, secret detection, and Semgrep or OpenGrep compatibility. That makes it feel less like a single product category and more like a deliberate mix of primitives. Fast local checks cover the common cases. Rule compatibility keeps it from becoming an island.

DimensionfoxguardRegex secret scannerTraditional SASTSemgrep-only workflow
SpeedLinter-fastFastOften slowerFast enough, but depends
PrecisionAST-basedLowHigh to mediumMedium to high
Taint trackingYesNoSometimes expensiveLimited depending on rules
Developer experienceLocal-first, TUIMinimalOften CI-centricCLI-centric
PQC complianceYesNoRareRare
AI-agent readinessMCP integrationNoNoNot native

foxguard’s pipeline is a compromise on purpose. It keeps the scan fast by summarizing first, then tracing only the paths that matter.

{
  "path": "src/auth.py",
  "rule_id": "taint.file-upload-to-shell",
  "severity": "high",
  "location": {"line": 84, "column": 12},
  "taint_hops": 2,
  "confidence": 0.78,
  "cnsa2_deadline": null
}

The engine: parallel file walking, parsing, and summaries

Under the hood, foxguard is very Rust-shaped. The scanner walks the tree with ignore::WalkBuilder, which means it respects .gitignore and avoids wasting cycles on junk. It then fans out across files with rayon, which is the right move for a workload that is embarrassingly parallel until it is not.

The more interesting move is the pre-pass. Instead of scanning each file as if it were isolated, foxguard builds alias and cross-file summary data first. That gives later rules enough context to connect imports, names, and simple dataflow without doing full whole-program analysis. It is a pragmatic midpoint: more context than grep, less cost than symbolic execution.

Taint tracking without going full symbolic execution

This is the core idea that makes foxguard feel different. Taint tracking usually implies heavyweight analysis, but foxguard appears to take a narrower path: intraprocedural flow plus cross-file summaries. That gives it enough signal to trace source-to-sink paths across files while avoiding the cost explosion of exhaustive interprocedural reasoning.

The tradeoff shows up in the data model. The Finding struct carries taint_hops and confidence, which is a very honest way to describe uncertainty. As the path gets longer, the confidence drops. That is useful because it tells the developer whether they are looking at a crisp finding or a weaker chain that still deserves inspection.

A close-up code path splits through several file cards before reaching a sink. The line gets thinner at each hop, and a small gauge drops as the path lengthens. It explains how foxguard keeps taint tracking readable by showing confidence decay instead of pretending every path is equally strong.
foxguard’s taint model is not full symbolic execution. It is a controlled path trace with explicit confidence decay.

The other reason this matters is explainability. A developer can see where the path starts, how many hops it took, and how confident the scanner is in the result. That makes the output easier to trust, especially when the tool is meant to run often and quickly.

Why PQC compliance changes the product category

foxguard does something uncommon for a developer scanner. It treats post-quantum cryptography migration as a first-class scanning problem. The project’s compliance logic maps cryptographic findings to CNSA 2.0 deadlines, which pushes the tool beyond appsec into migration planning. That is a different kind of value. It is not only telling you what is broken today. It is helping you inventory what will become unacceptable over a long transition window.

That broadens the audience. A regular secret scanner is mostly for code hygiene. A PQC-aware scanner can also be useful to teams responsible for long-lived systems, regulated environments, or infrastructure that must survive algorithm migration without surprise.

Questionfoxguard answerWhy it matters
What should we fix now?Security findings and secretsImmediate remediation
What cryptography ages badly?CNSA 2.0 annotated findingsMigration planning
What is the output format?Reports and CBOMWorks for engineering and audit
Can it live in the inner loop?YesAdoption improves when scanning is local

The terminal as a triage surface

The TUI is not decoration. It is the place where foxguard turns scanning into review. A full-screen terminal interface makes sense here because the user is often already in a terminal when they run a pre-commit check, inspect a diff, or triage a changed-file scan. The product is not just detection. It is inspection, baselining, and explanation in the same place.

That is a good design fit for a fast scanner. If results arrive quickly, they should also be easy to sort, explain, and dismiss without jumping to a separate dashboard. foxguard seems to understand that the human bottleneck is usually attention, not raw detection power.

A tool built for humans and agents

The inclusion of MCP support and a Claude Code plugin makes foxguard feel unusually forward-looking. It is still a human tool first, but it is also legible to AI agents that need a scanner they can call directly. That matters because the next layer of developer tooling will not only be interactive for people. It will also be callable by software that is trying to help write, review, and repair code.

That is a smart place to end up. The strongest tools rarely pick between human and machine use. They make the output structured enough for automation and understandable enough for people. foxguard’s mix of JSON, SARIF, CBOM, and TUI triage suggests it is aiming for exactly that middle ground.