Security

Multi-scanner audit with LLM triage

Point it at a repository and it provisions a machine, runs eight static-analysis engines, merges everything into one SARIF document, has a reasoning model triage the pile, writes a report to S3, and terminates itself. The interesting part is not the scanning; it is throwing away the nine findings out of ten that nobody should read.

Type
Open source · MIT
Stack
Shell · Python · AWS EC2 · S3
Engines
gitleaks · OpenGrep · Bandit · Trivy · checkov · osv-scanner · CodeQL
Triage model
Reasoning model via OpenRouter

View on GitHub

The problem

Run five static-analysis tools over a real codebase and you get several hundred findings. Most are duplicates of each other, a large share are false positives, and the handful that would actually get you breached are buried somewhere in the middle. The bottleneck in security tooling has not been detection for years; it is triage.

Worse, the findings that matter least are the loudest. Dependency CVEs with no reachable call path generate more noise than an authorization check that is missing entirely, because the second one requires understanding what the code is supposed to do.

How it works

Everything runs on an ephemeral instance that destroys itself when the job finishes, so a forgotten audit cannot become a running bill. Scanners execute sequentially with pinned versions; CodeQL runs last and isolated because it is the expensive one.

REPO gitleaks OpenGrep Bandit Trivy checkov osv-scanner CodeQL PINNED VERSIONS MERGE one SARIF REDACT strip secrets BULK TRIAGE dedupe · rank 1–5 SEMANTIC PASS authz · IDOR REPORT → S3

Triage runs in two passes: a bulk pass that deduplicates and ranks by exploitability, then a deeper semantic pass over the high-risk survivors that hunts for logic and authorization bugs no pattern matcher will find.

Decisions that mattered

Secrets are redacted before any model call, by pattern match and regex masking.

A secrets scanner's output is, by definition, full of secrets. Sending that to a third-party API to be triaged would leak exactly what the tool was built to find. This is the constraint the rest of the pipeline is designed around.

Everything emits SARIF, and merging happens before triage.

A common format is what makes cross-engine deduplication possible at all: the same vulnerability found by three tools should cost the reviewer one decision, not three.

The instance terminates itself when the run completes.

Audit tooling is used irregularly, which is exactly the usage pattern that leaves instances running for months. Self-termination makes the safe behaviour the default one.

A second semantic pass runs only on high-risk findings.

Deep reasoning over every finding is unaffordable and mostly wasted. Spending it on the ranked survivors is where authorization and IDOR bugs actually surface.

Where it came from

This is the generalized, open-source form of a pipeline I built and ran in production. On a real codebase it reduced 345 raw findings to 33 verified issues, nine of them critical: remote code execution, server-side request forgery, insecure direct object references, and exposed credentials. The repository contains no findings, target names, or customer data; the sample report is explicitly synthetic.

Other work