Foxguard Security Scanner

repository·main·Indexed 42 days ago

https://github.com/0sec-labs/foxguard

A fast, local security scanner written in Rust designed to detect code vulnerabilities, secrets, dependency risks, and cryptographic weaknesses. Version 0.14.0 features 200+ built-in rules across 12 source languages and supports taint tracking as part of the 0sec cybersecurity harness.

Tokens
78.8K
Snippets
181
Records
355
Agent score
55%

What's inside Foxguard

  1. Overview of foxguard capabilities and language support

    main

    foxguard is a high-speed security scanner written in Rust designed for fast local feedback. It detects vulnerabilities such as:

    • SQL injection
    • XSS
    • SSRF
    • Hardcoded secrets
    • Command injection
    • Weak crypto
    • Unsafe deserialization
    • Framework-specific mistakes

    Supported Languages: JavaScript, TypeScript, Python, Go, Ruby, Java, PHP, Rust, C#, Swift, Kotlin, and Haskell.

    Rule Formats:

    • Uses built-in rules by default.
    • Supports a Semgrep/OpenGrep-compatible YAML subset, allowing you to use existing rules.
  2. Status of deferred PHP taint skip-shape assessments

    main

    Several PHP-specific taint skip-shape assessments are currently deferred due to engine limitations. These include:

    • doctrine-orm-dangerous-query: Blocked by lack of PHP AST search (cannot enforce QueryBuilder scope) and lack of a concat-literal source matcher.
    • laravel-sql-injection: Blocked by lack of PHP AST search and the absence of an argument-position-aware sink primitive (CallArgSink{method, arg_index}).
    • laravel-unsafe-validator: Blocked by requirements for new primitives (typed-param sources, metavariable-pattern property sources, and chained :: static sinks).
    • laravel-api-route-sql-injection: Blocked by the need for PHP :: scoped-call Call support and closure-parameter source seeding.
  3. Understand Semgrep migration readiness report dispositions

    main

    The semgrep-readiness report categorizes imported rules into three dispositions to help you understand the compatibility of your rule set:

    • exact: The importer successfully emitted a live rule with no reduction in functionality.
    • degraded: The importer emitted a live rule but had to reduce its capability. Examples include ignored fix-regex (unsupported-fix-regex), skipped unsupported pattern-not-regex, or partially unsupported language declarations.
    • skipped: The importer could not emit a live rule. This happens if the rule was routed to an engine bridge, the language could not be mapped, or the file transaction failed (file-import-failed).

    Note: exact indicates successful rule emission, but it is not a claim of empirical finding parity with the Semgrep CLI.

  4. Understand the foxguard taint engine scope and capabilities

    main

    The foxguard taint engine is designed for rule authors to detect flows from untrusted sources to dangerous sinks. Unlike pure AST pattern matching, it tracks whether data actually reaches a sink, providing higher precision.

    Core Semantics

    • Intraprocedural: Each function body is analyzed independently.
    • Flow-insensitive: Statements are processed in source order. Reassigning a tainted variable to a clean value drops the taint.
    • Propagation Rules:
      • Attributes: x.y is tainted if x is tainted (one level).
      • Subscripts: x[k1][k2] is tainted if any link in the chain or the root is tainted.
      • Wrapping-calls: bytes(x) is tainted if x is tainted.
      • Method-calls: x.foo() is tainted if the receiver x is tainted.
      • Interpolation: Python f-strings or JS template literals are tainted if any interpolated expression is tainted.
      • Destructuring: For a, b = expr1, expr2, taint is matched by position. For opaque RHS like a, b = helper(), all LHS targets are conservatively tainted.
    • Sanitizers: Any call matching a TaintSpec.sanitizers entry produces a "clean" value, short-circuiting the taint flow.
    • Interprocedural Support: Supports same-file return propagation (v1) and bounded multi-hop cross-file taint for specific languages (Python, JS, Go, Java, C#, Ruby, PHP, Kotlin).
  5. Understand Semgrep registry coverage metrics

    main

    The Semgrep registry coverage report measures the compatibility of foxguard's Semgrep-compat YAML loader (src/rules/semgrep_compat.rs) against the official semgrep-rules registry.

    Rules are classified into two main categories:

    1. Loaded OK: The loader successfully produces a live matcher for the rule.
    2. Skipped: The rule is skipped because of a single unsupported operator or key.

    Common skip reasons include:

    • mode: taint (unsupported shape): Indicates a taint analysis rule with a structure not yet supported by the current implementation.
    • generic mode (languages: [generic]): Indicates the rule targets a language for which foxguard lacks a tree-sitter grammar.
  6. Rule pack layout convention

    main

    Rule packs follow a hierarchical directory structure:

    rules/<area>/<class>/

    • <area>: A coarse topic (e.g., kernel, compliance, vendor, cloud).
    • <class>: A specific bug class or rule grouping.
    • Each <class>/ directory contains the Semgrep-compatible YAML rules.
    • An optional queries/ subdirectory can be included for companion CodeQL queries (used by engine: codeql rules). The foxguard loader automatically skips queries/ subdirectories to prevent metadata from reaching the YAML parser.
  7. Understand foxguard YAML rule packs

    main

    foxguard includes a directory of Semgrep-compatible YAML rule packs that are embedded directly into the binary at compile time. By default, running foxguard <target> executes these bundled packs (such as the kernel/dirty-frag-class pack) alongside the core Rust rules.

    These packs follow a specific directory structure and are automatically loaded by the RuleRegistry during execution. The engine supports Semgrep-compatible syntax including pattern-regex, pattern-not-regex, paths.include, paths.exclude, languages, severity, and metadata fields like metadata.cwe and metadata.references.

  8. Benchmark modes: default vs compat

    main

    The benchmark suite operates in two distinct modes to serve different comparison goals:

    default mode

    • Goal: Product comparison.
    • Logic: Compares foxguard's built-in rules against the auto rulesets of Semgrep and OpenGrep.
    • Output: Results written to benchmarks/results-default.md.

    compat mode

    • Goal: Same-rules engine comparison.
    • Logic: All three tools (foxguard, Semgrep, and OpenGrep) use the shared YAML rules located in benchmarks/compat_rules/. In this mode, foxguard runs with --no-builtins --rules benchmarks/compat_rules to ensure the comparison is focused strictly on the external ruleset.
    • Output: Results written to benchmarks/results-compat.md.
  9. How foxguard reduces noise and false positives

    main

    foxguard includes a built-in noise filter in src/engine/scanner.rs that runs by default to reduce the false-positive (FP) footprint. The engine automatically skips files in the following directories:

    • vendor/
    • node_modules/
    • __fixtures__/
    • __mocks__/
    • dist/
    • build/
    • .next/
    • coverage/
    • .cache/

    Additionally, it applies the following heuristics to skip files:

    • Any .min.js or .min.css files.
    • Any file where the first line is longer than 1000 characters (a minified-bundle heuristic).
  10. Understand PHP AST search-pattern limitations in foxguard

    main

    A critical limitation in the current version of foxguard is that AST pattern: and pattern-inside search matching is a no-op for PHP.

    Because PHP patterns are currently parsed as bare text/HTML by the underlying tree-sitter-php parser (rather than being wrapped in <?php tags), the first_meaningful_node returns a text node that matches no actual code nodes.

    Consequences for users/rule-writers:

    • Under-matching: Any rule attempting to use pattern-inside to scope a sink (e.g., to ensure a where() call is specifically on a Laravel DB::table() chain) will fail to find any matches, causing the rule to never fire.
    • Over-matching: If you attempt to bypass this by removing the pattern-inside scope, the rule will match the method names (like where, select, or join) on every object in the codebase, leading to massive amounts of false positives (catastrophic over-match).
    • Current Workarounds: PHP is currently only supported via the dedicated taint engine (php_taint.rs) or pattern-regex rules, which do not rely on the AST search matcher.
  11. Understand Go mode: taint skip shapes

    main

    In Foxguard's Go implementation of mode: taint, certain Semgrep rules are skipped if they cannot be faithfully implemented without 'over-matching' (triggering false positives on the rule's own negative test cases).

    Currently, two major rule shapes are implemented:

    1. hardcoded-jwt-key: Detects hardcoded byte-slice literals used as signing keys.
    2. gorm-dangerous-method-usage: Detects dangerous SQL method calls in GORM when arguments are tainted by an *http.Request.

    Other complex rules involving multiple primary labels or multi-statement metavariable unification (like grpc-server-insecure-connection or handler-assignment-from-multiple-sources) are currently deferred because the engine's dataflow model cannot express them without losing precision.

  12. Understand the foxguard GitHub App permission and event requirements

    main

    To function correctly, the GitHub App must be configured with specific repository permissions and subscribed to specific webhook events. Over-scoping or under-scoping will cause runtime failures.

    Required Repository Permissions

    • contents: read: Used to clone the PR head.
    • pull_requests: read: Used to list PR files, bot summary comments, and legacy comments.
    • pull_requests: write: Used to create/update the PR summary and delete legacy inline comments.
    • checks: write: Used to create the foxguard check run with annotations.

    Required Subscribed Events

    • pull_request: Triggers the scan and review loop.
    • installation: Synchronizes the installation_store.rs registry.
    • installation_repositories: Synchronizes the registry when repositories are added/removed from an installation.