Sub-second local security scanning for real codebases.
130+ built-in rules · 10 languages · taint tracking for Python, JavaScript, Go · single Rust binary · Semgrep-compatible YAML bridge
foxguard.dev · npm · crates.io
Security scanners are slow. 10 seconds, 30 seconds, sometimes a minute. So developers don't run them locally — they get pushed to CI, findings pile up in PRs, and nobody looks at them.
foxguard fixes this by being fast enough that you never notice it's there. Same scan, 0.03 seconds instead of 10. You can run it on every save, every commit, every push. Security feedback becomes instant.
npx foxguard .src/auth/login.js
14:5 CRITICAL js/no-sql-injection (CWE-89)
SQL query built with template literal interpolation
src/utils/config.py
7:1 HIGH py/no-hardcoded-secret (CWE-798)
Hardcoded secret in 'api_key'
WARNING 2 issues in 5 files (0.03s): 1 critical, 1 high, 0 medium, 0 low
- Fast enough to leave on. foxguard is built for local runs, pre-commit hooks, and changed-file scans instead of “security later in CI”.
- Useful before you tune anything. The default value is built-in framework-aware rules for common real-world mistakes across JavaScript, Python, Go, Ruby, Java, PHP, Rust, C#, and Swift.
- Taint tracking built in. Intraprocedural taint flow from framework sources (Flask, Django, FastAPI, Express, Next.js, Hono, Gin, net/http) into sinks like
eval,exec, SQL execute, and SSRF — no rule writing required. - Adoption-friendly. If you already have Semgrep/OpenGrep YAML, foxguard can load a focused compatible subset on top of built-ins so migration is incremental instead of all-or-nothing.
See docs/precision.md for per-rule precision tiers and our false-positive methodology.
npx foxguard . # scan the repo
npx foxguard --changed . # only modified files
npx foxguard secrets . # leaked credentials and private keys
npx foxguard init # install a local pre-commit hookRust + tree-sitter for AST parsing + rayon for parallelism. No JVM startup, no Python interpreter, no network calls, no rule download step. Just a native binary that reads your files and reports findings.
130+ built-in rules across 10 languages. SQL injection, XSS, SSRF, command injection, hardcoded secrets, weak crypto, unsafe deserialization, log injection, and framework-specific checks for Express, Django, Rails, Spring, Laravel, Gin, .NET, and iOS. Python, JavaScript, and Go also get an intraprocedural taint engine that follows untrusted input from framework request sources into dangerous sinks.
Also scans for leaked credentials (AWS keys, GitHub/GitLab/Slack/Stripe tokens, private keys) with redacted output. Loads Semgrep-compatible YAML rules with --rules if you have existing ones. Outputs terminal, JSON, or SARIF for GitHub Code Scanning.
foxguard dogfoods itself — it scans its own Rust source in CI on every push.
foxguard is not trying to be a full Semgrep or OpenGrep drop-in replacement.
The intended model is:
- foxguard built-ins for fast local feedback
- Semgrep/OpenGrep-compatible YAML subset as an adoption bridge
- Semgrep/OpenGrep themselves when you need the broadest external rule ecosystem
That boundary is deliberate. It keeps local scans fast, rule support understandable, and compatibility claims testable.
npx foxguard . # no install needed
brew install peaktwilight/tap/foxguard # Homebrew (macOS/Linux)
cargo install foxguard # crates.ioEditor: Install the VS Code extension — scans on save, shows findings as underlines.
Reproducible benchmarks via ./benchmarks/run.sh. Numbers below are from a local run on an Apple Silicon laptop with foxguard 0.4.0, semgrep 1.156.0, tokei 14.0.0. LoC is counted by tokei, scoped to the target language only (no vendored HTML/JSON).
| Repo | Files | LoC | foxguard | Semgrep | Speedup |
|---|---|---|---|---|---|
| express (framework) | 141 | 15,804 JS | 0.11s | 4.80s | 45x |
| flask (framework) | 83 | 14,029 Py | 0.08s | 5.70s | 73x |
| gin (framework) | 99 | 17,669 Go | 0.07s | 4.61s | 63x |
| sentry (production) | 8,539 | 1,291,606 Py | 12.19s | 164.53s | 13x |
Sentry is the larger-corpus stress target added under issue #8: a real production monitoring platform at ~1.3M Python LoC. foxguard scans the whole tree in ~12 seconds (~106k LoC/sec); Semgrep with --config auto takes ~2m45s on the same tree. Run on one machine — your numbers will vary; reproduce locally with ./benchmarks/run.sh.
To reproduce: ./benchmarks/run.sh (add BENCH_SKIP_LARGE=1 for the quick matrix only). See benchmarks/README.md for the reproduction recipe.
| Language | Rules | Frameworks |
|---|---|---|
| JavaScript/TypeScript | 27 | Express, Next.js, Hono, Fastify, SvelteKit, Deno, JWT, XSS, taint |
| Python | 32 | Flask, Django, FastAPI, CSRF, session, intraprocedural taint |
| Go | 11 | Gin, net/http, TLS, intraprocedural taint |
| Ruby | 10 | Rails, mass assignment, CSRF |
| Java | 10 | Spring, XXE, deserialization |
| PHP | 10 | Laravel, file inclusion, unserialize |
| Rust | 10 | unsafe, transmute, TLS |
| C# | 10 | .NET, LDAP, XXE, CORS |
| Swift | 10 | iOS keychain, transport, WebView |
- Changed-file scans for tight local loops
- Repo-local baselines so legacy findings stop blocking adoption
- Secrets scanning alongside code scanning
- JSON and SARIF output for CI and GitHub Code Scanning
- Semgrep/OpenGrep YAML subset when teams already have rule investments
Load existing Semgrep/OpenGrep YAML rules with --rules. Supports pattern, pattern-regex, pattern-either, pattern-not, pattern-inside, pattern-not-inside, metavariable-regex, and paths.include/exclude. This supported subset is parity-tested in CI against the real semgrep CLI. See COMPATIBILITY.md.
foxguard does not currently aim to support multiple unrelated external rule formats. The compatibility target is the focused Semgrep/OpenGrep YAML subset above.
name: Security
on: [push, pull_request]
jobs:
foxguard:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- uses: PwnKit-Labs/foxguard/action@v0.4.0
with:
path: .
severity: medium
fail-on-findings: "true"
upload-sarif: "true"Findings show up in Security → Code Scanning.
npx foxguard@latest . # scan
npx foxguard@latest --format sarif . > out.sarif # SARIF output
npx foxguard@latest secrets . # secrets[](https://github.com/PwnKit-Labs/foxguard)repos:
- repo: https://github.com/PwnKit-Labs/foxguard
rev: v0.4.0
hooks:
- id: foxguard
- id: foxguard-secretsOr run foxguard init to install a git hook directly.
foxguard auto-discovers .foxguard.yml from the scan path upward.
scan:
baseline: .foxguard/baseline.json
rules: ./semgrep-rules
secrets:
baseline: .foxguard/secrets-baseline.json
exclude_paths:
- fixtures
- testdata
ignore_rules:
- secret/github-tokenFor one-off, deliberate code patterns, you can suppress code-scan findings inline instead of adding them to a baseline.
// Ignore the next code line for one rule
// foxguard: ignore[js/no-ssrf]
fileContent = fetch(userControlledUrl);
// Ignore the current line for one rule
fileContent = fetch(userControlledUrl); // foxguard: ignore[js/no-ssrf]
// Ignore the current line for all foxguard code findings
eval(userInput); // foxguard: ignoreNotes:
- Inline ignores currently apply to code scanning findings, not
foxguard secrets. - Rule IDs must match exactly, for example
js/no-ssrf. - Comment-only directives apply to the next non-empty, non-comment code line.
- Supported comment styles are
//and#, depending on the language.
Adding a rule is one struct implementing a trait. See CONTRIBUTING.md.
Open-source adversarial security for the agentic AI era. foxguard is one piece of the open-source PwnKit Labs stack:
- pwnkit — AI agent pentester (detect)
- foxguard — Rust security scanner (prevent)
- opensoar — Python-native SOAR platform (respond)
MIT
