SecAudit
Open sourceMITDefensive use only

Finds the flaw.Shows the proof.

SecAudit audits a source repository, and a running target where ownership has been asserted. Every finding carries its file, its line, and the path from untrusted input to the dangerous call.

Available as a Claude Code plugin or as a standalone tool. No API key, no paid plan, no network access, zero runtime dependencies.

one finding, in fullTAINT-JS-CMDI
12const host = req.query.host
13exec('ping -c 1 ' + host)
  • CWE-78 · Critical
  • L12 → L13 · argument 0
  • reachable · refutable

The CWE, the two lines the finding spans, and the argument that carried the value, printed as the tool prints them. A pattern matcher flags line 13 on sight; this engine reports it because line 12 reaches it, and publishes the path behind the verdict.

What it does

A single command scans the code and reports what it finds.

Three stages, none of which requires an account, a network connection or a model.

  • Targetsecaudit ./repoA checkout, a single file, or a running URL once ownership has been asserted.
  • Analysis115 detectors · taintPattern detectors across 15 languages, and a pass that follows untrusted input from its entry point to the call that consumes it.
  • Outputsarif · sbom · openvex · craEvery finding with its file, its line and its path. SARIF for code scanning; the SBOM, the dependency verdicts and the CRA evidence pack are produced by the same run.

Detection rate

Detection rate, measured on two corpora.

Recall is the share of existing vulnerabilities found. Precision is the share of reported findings that are real. F3 combines the two and weights recall nine times heavier, on the basis that a missed vulnerability costs more than a false alarm. All figures are Tier 0: no LLM, no external scanners, no network. The external result on the left is the material one — a third-party corpus, third-party labels and a third-party scorer.

RealVuln — external corpus, Python

62 of 66 real vulnerable repositories, labelled independently of this project and scored by the benchmark's own scorer. Semgrep, the published rule-based baseline, scores 17.7% on the same corpus. This corpus is Python; the JavaScript side is measured separately against 573 labelled sinks in real npm packages and finds 54.4% of them.

  • 61.2%F3 (recall × 9)
  • 65.6%precision
  • 60.7%recall
  • 62of 66 repos

Internal fixtures — regression floor

62 labelled flaws and 62 false-positive traps, each trap a safe implementation of the feature its vulnerable twin implements. These figures establish that the engine still works. They are not a prediction for any other codebase.

  • 98.4%recall
  • 100.0%precision (upper bound)
  • 98.6%F3 (recall-weighted)
  • 0false positives on traps

The same scorer reports a stricter reading of the same run at F3 57.0%. That is the figure to cite for any purpose other than comparison against the benchmark's own baselines. Raw scorer output is committed to the repository, and CI fails when a figure on this page no longer matches it.

Disclosureread before citing the figure

The score is no longer blind, and that qualifies it.

30 runs on a single corpus. In the first, the engine had not seen the corpus. In the runs since, the rules added were selected by reading this benchmark's own false negatives.

Every rule added is of a kind any SAST ships, so no rule is fitted to a fixture. The selection, however, was corpus-informed: the gap between 12.5 and 61.2 is the size of that advantage. 12.5 is the conservative figure for an unseen codebase. The honest successor to this measurement is a benchmark this repository has not read.

Coverage15

Fifteen languages, with recall reported for each.

Every language in the fixture corpus has a paired vulnerable and safe implementation. The figures below are what the deterministic tier scores on each, including the languages that fall short of full marks.

  • C#100%
  • Dart100%
  • Dockerfile100%
  • Go100%
  • Java100%
  • JSON100%
  • Kotlin100%
  • PHP100%
  • Info.plist100%
  • Python100%
  • Ruby100%
  • Rust100%
  • Terraform100%
  • YAML100%
  • JavaScript94%

Recall on the shipped fixtures, which were written alongside the detectors. Depth varies by language: Python and JS/TS receive taint analysis and the structural passes; the remainder receive the pattern pack. The per-language matrix in the repository is generated from the code.

AuthorizationPreToolUse

Active testing requires an asserted authorization.

SecAudit audits a running target as well as a checkout, and that capability is gated. Passive reconnaissance requires no permission. Active testing against a live target is refused by a deterministic PreToolUse hook before the command executes, rather than by instructing a model. Once ownership is asserted, the same command proceeds. A committed scope file does not qualify: it arrives with the clone and is not an assertion made by the operator.

active-scan-guard
$ nuclei -u https://acme.example

18 active patterns blocked and 12 passive patterns allowed, asserted by the hook's own self-test on every build, on Linux and on Windows.

Evidence2026-09-11

The documents an auditor requests, produced by the same scan.

A single run produces an inventory of shipped components, a verdict on each dependency advisory, and a mapping from every finding to the clause it bears on. Vulnerability-handling obligations under the EU Cyber Resilience Act take effect on 2026-09-11. Findings additionally carry an OWASP ASVS 5.0 chapter and, where the requirement text supports it, a PCI DSS 4.0.1 requirement.

The pack is an input to a compliance process, not a certificate, and states this in its own disclaimer. Requirements that cannot be asserted from a source scan are listed as refused, with the reason.

--format cyclonedx

CycloneDX 1.6 SBOM

Components, licences, hashes.

--format openvex

OpenVEX register

A status and a reason per advisory.

--format cra

EU CRA evidence pack

Findings mapped to Annex I clauses.

--format sarif

SARIF 2.1.0

Uploads to GitHub code scanning.

Limitations

What the engine misses, generated from the engine.

A hand-maintained limitations page is accurate for one release and understates thereafter. This one is produced from the detector table and the measured misses, so it cannot fall behind the code.

A clean report is not an all-clear until the full limitations page has been read. Every report the tool writes states its own bounds: a scan that could not reach something records that rather than omitting it.

  • 1

    Business-logic flaws

    The rules being violated belong to the product and are recorded nowhere the analyzer can read. Only the model tier reaches this class, and it has no measured score.

  • 2

    Broken access control at the handler

    2 of 76 labelled cases detected on the external corpus. Most of those labels sit on a function definition: the flaw is a property of everything the handler returns.

  • 3

    Race conditions and TOCTOU

    Detection requires an interleaving model. A lexical pass reads a single execution, not two concurrently.

  • 4

    Code behind a dynamic dispatch

    Calls through a variable, a decorator or a dispatch table are not resolved. Inferring that edge is how an analysis begins attributing real sinks to the wrong function.

Installation

Two lines in Claude Code, or a single pip install.

The two most commonly used. There are 6 in total: the MCP server, the GitHub Action, the container image and the pre-commit hooks are the remaining four. All run the same engine, and none is a reduced version of another.

  • 115deterministic detectors
  • 62labelled fixture flaws
  • 45CI gates
  • 57CWEs mapped to ASVS 5.0

As a Claude Code plugin:

/plugin marketplace add mtvrkan/secaudit
/plugin install secaudit@secaudit-kit

Standalone — no Claude Code, no API key, no plan, zero runtime dependencies. Runs in CI, under cron, and on an air-gapped host:

python3 -m secaudit_core.cli ./repo --min high
python3 -m secaudit_core.cli ./repo --format sarif   # GitHub code scanning
python3 -m secaudit_core.cli ./repo --format cra     # EU CRA evidence pack

Run the audit before it is requested.

SecAudit scans a repository, or a running target under declared ownership. The deterministic tier requires only Python, and it reports the limits of its own coverage.