bravos
Shift-left security that runs with every commit.
Threat model, code graph, SAST and an agentic pentest on every pull request, ending in a test that guards the fix.
pipx install bravos+1 exposure declared on the new route: #orders-api → #idorEvery risk mapped, with 5 still open
02 · Threat modelGuardLink
Every risk, mapped where it lives.
Written next to the code, drawn four ways.
03 · Code graph
Your codebase as a map. Every route to what it touches.
04 · SAST
Findings, sorted by what can reach them.
Deterministic analysis, placed on the code graph. Nothing is sent anywhere.
- 61all findings
- 23on a path from an entry point
- 9corroborated or plausible
- 2fail the gate
- User-controlled URL reaches http.get
src/uploads/import.ts:31viaPOST /uploads/importfail@exposes #uploads to #ssrf - No ownership check before db.orders.findAll
src/api/orders.ts:42viaGET /orders/exportfail@exposes #orders-api to #idor - Unescaped HTML rendered in admin notes
src/admin/notes.tsx:66viaPOST /admin/noteswarn@exposes #admin to #stored-xss - Model output passed to a tool unchecked
src/agent/tools.ts:19viatool: send_emailwarn@exposes #support-agent to #prompt-injection - Signature compared with ==
src/webhooks/payments.ts:14viaPOST /webhooks/paywarn - Path built from the upload filename
src/uploads/store.ts:27viaPOST /uploads@mitigates … using #path-normalise - Secret read from env written to a log
src/admin/settings.ts:18no entry reaches itwarn@exposes #admin to #secret-leak - Dependency with a published advisory
package-lock.jsonno entry reaches it - Hard-coded key in a test fixture
tests/fixtures/pay.ts:3no entry reaches it - Regex with a nested quantifier
src/lib/slug.ts:9no entry reaches itreview: noise
showing 10 of 61 · sample
05 · Proven
Then it tests a running copy, and keeps the proof.
12 tracked · 0 reached a verdict
- Round 1unauthenticatedqueued0/14 probes3 cleared
- Round 2customerqueued0/19 probes2 proven1 needs review4 cleared
- Round 3adminqueued0/14 probes1 cleared1 couldn’t test
@confirmed lines written back next to the code“Couldn’t test” is listed, not hidden. Nothing found never means not tested.
06 · Tests in CI
Each proof becomes a test that guards the fix.
src/api/orders.ts41 const orders = await db.orders.findAll({42+ where: { customerId: session.user.id },43 })
bravos high #orders-api → #idor — confirmed (replay) — still exploitable
- ✗Failed: bravos security gatefailed · 2 breaches
- ✗Failed: bravos replay2 stored tests · 2 still exploitable
- ✓Passed: guardlink validatemodel current
| severity | asset → threat | verdict | location | outcome |
|---|---|---|---|---|
| ✗ bravos security gate — failed · 2 breach(es) · 2 confirmed of 12 tracked | ||||
| high | #orders-api → #idor | confirmed · replay | src/api/orders.ts:42 | still exploitable |
| high | #uploads → #ssrf | confirmed · replay | src/uploads/import.ts:31 | still exploitable |
$ bravos replay replaying 2 stored tests from the ledger ✗ #orders-api → #idor still exploitable 200 OK, not their order ✗ #uploads → #ssrf still exploitable internal host reached$ bravos ci --reporter github ✗ bravos security gate — failed · 2 breach(es)
bravos ci exits non-zero on a breachHow it fits
What Bravos provides, and what you bring.
Constant · provided by Bravos
Shared context
The state every run reads and writes back.
- GuardLink threat model
- Threat ledger
- Template registry
- Code graph
commandsannotateledgertemplategraphdiffsast
- Constant, provided by Bravos
- Changes over time, you bring it
- 01AnnotateThe threat model, written into your code.
annotate - 02PlanA brief becomes a scan plan you approve.
intake · plan - 03PentestProbes run in a disposable copy, with real logins.
run · auto - 04LedgerEvery result is recorded; stored probes replay.
ledger · replay - 05Write backVerdicts go into the code; CI gates on them.
ci · diff
bravos
Secure your next pull request.
pipx install bravosInstall in your editor
code --install-extension bravos.bravoscursor --install-extension bravos.bravoswindsurf --install-extension bravos.bravosOr search “Bravos” in the Extensions panel of any VS Code fork. The identifier is bravos.bravos, on the VS Code Marketplace and Open VSX.
Built on GuardLink, threat model as code, and Cert-X-Gen, pentest as code. See licences