NEWBravos is availableCreate your account

bravos

Shift-left security that runs with every commit.

Bravos makes the coding agent you already use work your threat model, code graph, SAST and authorized pentests, then gates every pull request and keeps a test that guards each fix.

npm install -g @bugb-technologies/bravos

Open your project in your coding agent (Claude Code, Codex, Cursor…), then paste this.

Add order export pinecart · #482running
AssetsThreatsControls#auth#checkout#orders-api#uploads#support-agent#broken-auth#csrf#idor#sqli#ssrf#prompt-inj…#session-rot…#csrf-token#prepared-st…#approval-gate@exposes #orders-api to #idor

+1 exposure declared on the new route: #orders-api → #idorEvery risk mapped, with 5 still open

02 · Threat modelThreat modelling

Every risk, mapped where it lives.

Written next to the code, drawn four ways.

Assets 8Open 5Mitigated 7Controls 7
ASSETSTHREATSCONTROLS#auth#checkout#orders-api#uploads#webhooks#admin#support-agent#broken-auth1 exp · 0 open · 1 mit#credential-stuffing1 exp · 0 open · 1 mit#csrf1 exp · 0 open · 1 mit#idor1 exp · 1 open · 0 mit#sqli1 exp · 0 open · 1 mit#path-traversal1 exp · 0 open · 1 mit#ssrf1 exp · 1 open · 0 mit#webhook-forgery1 exp · 0 open · 1 mit#stored-xss1 exp · 1 open · 0 mit#secret-leak1 exp · 1 open · 0 mit#prompt-injection1 exp · 1 open · 0 mit#excessive-agency1 exp · 0 open · 1 mit#session-rotation#rate-limit#csrf-token#prepared-stmts#path-normalise#hmac-verify#approval-gate
12 of 12 exposures and 7 mitigations drawnopen, by severitymitigatedhover or tab to tracepinecart · sample
5 open7 mitigated8 assets
Threat graphEvery risk tied to the part of the app it threatens, and the fix that covers it.
21 flows14 cross a trust boundary
Data flowData traced from the outside world, through your app and out again.
4 zones14 crossings, each marked
Trust zonesWhere data moves from one zone of trust to another, the crossing is marked.
4 direct8 two hops out
NeighbourhoodPick one asset and see everything it talks to, two hops out.
1 / 4

03 · Code graphTeam plan

Your codebase as a map. Every route to what it touches.

Lens
Where in this codebase is the risk?
API64orders/checkout/auth/admin-api/AGENT18WORKERS27refunds/exports/mail/DATA21models/migrations/WEB112storefront/admin/components/LIB41lib/TEST88tests/CONFIG6config/
5Open exposures5 files
7Controlsdeclared mitigations
21On a flowdeclared data flow
4Hotspotsby commit heat
18Entry pointsroutes and tools
8 layers · 20 folders · 377 filesopen exposure, by worst severityhover or tab to a folderpinecart · sample
377 files5 folders with an open risk
MapYour whole codebase on one screen. Risk shows up as heat.
15 pairs11 with no import between them
CouplingFiles that change together, linked, even where no import joins them.
18 ways in11 reach a risky call
Attack surfaceEvery way in, ranked by the risky calls it can reach.
2 unapproved (dashed)1 needs a person's sign-off
Agent reachWhat your AI assistant can do, and which of it nobody approved.
1 / 4

04 · SASTTeam plan

Findings, sorted by what can reach them.

Pre-PR gatefail
Fail the gate0
Warn0
On a path from an entry0of 61

Deterministic analysis, placed on the code graph. Nothing is sent anywhere.

Issues by evidence tier
T1 proven0, 0 reachable
T2 corroborated7, 4 reachable
T3 plausible11, 5 reachable
T4 hygiene29, 10 reachable
T5 set aside14, 4 reachable
Narrowed by reach
  1. 61all findings
  2. 23on a path from an entry point
  3. 9corroborated or plausible
  4. 2fail the gate
Issues
  • User-controlled URL reaches http.getsrc/uploads/import.ts:31via POST /uploads/importfail@exposes #uploads to #ssrf
  • No ownership check before db.orders.findAllsrc/api/orders.ts:42via GET /orders/exportfail@exposes #orders-api to #idor
  • Unescaped HTML rendered in admin notessrc/admin/notes.tsx:66via POST /admin/noteswarn@exposes #admin to #stored-xss
  • Model output passed to a tool uncheckedsrc/agent/tools.ts:19via tool: send_emailwarn@exposes #support-agent to #prompt-injection
  • Signature compared with ==src/webhooks/payments.ts:14via POST /webhooks/paywarn
  • Path built from the upload filenamesrc/uploads/store.ts:27via POST /uploads@mitigates … using #path-normalise
  • Secret read from env written to a logsrc/admin/settings.ts:18no entry reaches itwarn@exposes #admin to #secret-leak
  • Dependency with a published advisorypackage-lock.jsonno entry reaches it
  • Hard-coded key in a test fixturetests/fixtures/pay.ts:3no entry reaches it
  • Regex with a nested quantifiersrc/lib/slug.ts:9no entry reaches itreview: noise

showing 10 of 61 · sample

T1 provenT2 corroboratedT3 plausibleT4 hygieneT5 set asidepinecart · sample
Narrowed by reachSixty-one findings, narrowed to the two that need you today.
23 of 61 on a path from a way in
Placed on the code graphEach finding comes with the route that reaches it, and the risk it matches.
Deterministic. Nothing is sent anywhere.
The gateThe two that matter fail the pre-PR gate and hold the pull request. The rest warn or wait.
1 / 3

05 · ProvenAuthorized testing

Then it tests a running copy, and keeps the proof.

Against a target you own, with real logins, inside the scope you committed.

This run, accounted for

12 tracked · 0 reached a verdict

0confirmed0ambiguous0not run0refuted
  1. Login 1unauthenticatedqueued
    0/14 probes3 refuted
  2. Login 2customerqueued
    0/19 probes2 confirmed1 ambiguous4 refuted
  3. Login 3adminqueued
    0/14 probes1 refuted1 not run
The proof it keeps
0request and response pairs, one per confirmed finding
0retest kits kept in your repository, ready to replay
0@confirmed lines, recorded in the project's evidence ledger
0probes, every one inside the scope you committed

“Not run” and “ambiguous” are listed, not hidden. They prove nothing either way, so they stay untested.

3 logins · one run · 47 probesnumbers only · sample
47 probesevery one inside the scope you committed
Three logins, one runIt tests a running copy of your app that you own, signed in as each kind of user.
2 confirmed1 ambiguous1 not run8 refuted
Every risk accounted forEach tracked risk lands in a bucket. What didn't run, or ran without a clear answer, is listed, not hidden.
2 proofs2 retest kits saved
The proof it keepsEach proof is kept: the request, the response, and a retest kit that replays it.
1 / 3

06 · Gate and retest

Each proof becomes a test that guards the fix.

A retest kit in your repository, and a gate on every pull request.

The two retest kits stay in your repository. /bravos-recheck replays them after a fix; the nightly can replay them against a target you authorize.
Fix order ownership and import allowlist#487
src/api/orders.ts
41  const orders = await db.orders.findAll({42+   where: { customerId: session.user.id },43  })

Bravos #orders-api → #idor — confirmed, on a changed path

bravos security gate: failed
  • Passed: Threat model parses and resolvesModel validated
  • Passed: No undisclosed new exposurenothing new
  • Failed: No confirmed exploit on a changed path2 on changed files
Retest kits, replayed by /bravos-recheck
severityasset → threatverdictlocationoutcome
2 confirmed · 0 refuted of 12 tracked
high#orders-api → #idorconfirmed · kitsrc/api/orders.ts:42still exploitable
high#uploads → #ssrfconfirmed · kitsrc/uploads/import.ts:31still exploitable
▸ bravos security gate  ✓ Threat model parses and resolves  ✓ New claims meet the evidence bar  ✓ No undisclosed new exposure  ✗ No confirmed exploit on a changed path    Confirmed-exploitable claims on changed files, with no @ticket for them in that file:    high #idor on #orders-api — src/api/orders.ts:42    high #ssrf on #uploads — src/uploads/import.ts:31
Where it shows up
Your session/bravos-ship makes the same rulings before gh pr create
Beside your agentbravos watch: open, confirmed, tested and stale, live
GitHubthe gate's check on the pull request, and SARIF in code scanning
Before the fixBoth proofs still work. The gate fails a pull request that leaves a confirmed exploit on a changed file.
After the fix/bravos-recheck replays both retest kits. Both attacks are blocked, the ledger records them refuted, and the gate passes.
2 retest kits, in your repository
Every weekday nightPointed at a target you authorize, the nightly replays both kits, so the bug can't quietly come back.
1 / 3

How it fits

What Bravos provides, and what you bring.

CONSTANTCHANGES OVER TIMEPROVIDED BY BRAVOSdrivesSURFACEreads / writesSHARED CONTEXTruns onEXECUTIONdoes the workYOUR AGENTtests · writes backCODE & TARGETSbravosCLI · SKILLS

Constant · provided by Bravos

Shared context

The state every skill reads and writes back. It lives in your repository, shared through git.

  • Threat model
  • Hypothesis ledger
  • Retest kits
  • Code graph

skills /bravos-…contextannotatecodegraphsastreport

  • Constant, provided by Bravos
  • Changes over time, you bring it
  1. 01AnnotateThe threat model, written into your code./bravos-annotate
  2. 02TemplatizeEach open exposure becomes a testable security check./bravos-templatize
  3. 03ProveProbes run against a target you own, with real logins./bravos-prove
  4. 04LedgerEach result goes into the project's evidence ledger; kits replay after a fix./bravos-recheck
  5. 05GateA confirmed exploit on a changed path fails the pull request.bravos sync --ci

bravos

Secure your next pull request.

npm install -g @bugb-technologies/bravos
Install as a plugin in your coding agent

See the plugin guide for supported coding agents, installation instructions and differences from CLI setup. Every plugin needs the CLI above.

Only want the pull-request gate? uses: Bugb-Technologies/bravos-action@v1 needs no licence. GitHub Marketplace

See licences