Skip to content

Run the loop unattended

The verify tier is one command once it has a plan. This page covers the three steps that get you there, describe the scan, approve the plan, run it, and how to resume when it stops.

  • The verify tier’s dependencies: cxg, Docker, and a coding-agent CLI. See Install Bravos.
  • A target you are authorised to attack, and written authorisation you are willing to record. Read Authorization and blast radius first.
  1. Describe the scan. bravos intake takes a brief in your own words: the repository, the target URL, the identities, how deep to go. It turns that into a plan.

    Terminal window
    bravos intake "Thorough pentest of my app at /path/to/repo. It runs on
    http://127.0.0.1:9054, logins admin@example.com/Admin123! and
    user@example.com/User123!. Go deep and find chained exploits."

    The plan it prints carries a plan id, and it is the thing to argue with: the target it resolved, the login shape it read out of the repository, the lens rotation, the round budget, and an explicit list of what it could not determine.

  2. Approve it. Approving is the consent step; nothing before it sends traffic.

    Terminal window
    bravos intake --list
    bravos intake --show <PLAN_ID>
    bravos intake --approve <PLAN_ID>

    With no plans yet, --list says so:

    no plans yet — try `bravos intake "<what you want>"`

    --force approves a plan that still has unresolved items. The run then pauses when it reaches one.

  3. Run it.

    Terminal window
    bravos auto --plan <PLAN_ID>

    The plan supplies the target, the identities, and the attestation, so this is the whole loop: annotate, export, synthesise goals, probe, write back, report, rotate the lens, and repeat until it converges or halts.

If you already have a target running and identities captured, drive it directly:

Terminal window
bravos auto /path/to/repo --target http://127.0.0.1:9054 \
--attestation "Authorized self-test, Jane Doe, 2026-08-18"

--attestation is required for any run that sends traffic or edits code unless the run came from an approved plan. It is recorded in cxg’s audit log as your assertion that the target is yours to test.

Identities come from --cred, repeatable, or --creds-file:

Terminal window
bravos auto /path/to/repo --target http://127.0.0.1:9054 \
--cred alice:alice@example.com:Alice123!:admin \
--cred bob:bob@example.com:Bob123! \
--attestation "Authorized self-test, Jane Doe, 2026-08-18"

The role defaults to user; mark the privileged identity admin. Bravos reads the login shape off the target, logs each identity in, and saves a recipe so sessions re-authenticate mid-run and later runs reuse them.

The alternative is to capture sessions first with bravos env login and pass profile names with --auth. See Manage a test environment.

Flag Effect
--rounds N maximum rounds this invocation
--max-goals N cap goals per round
--concurrency N simultaneous goals (default 3)
--fast 1 template per goal and 1 mutation retry, instead of the default 2 and 2
--trust-annotations treat an existing @confirmed as settled instead of re-verifying it
--retest <THREAT_ID|KEY> forget a prior verification so the threat is tested again
--no-checkpoint no branch, no per-phase commits
--no-capture do not drive interactive logins inline; pause and print the cxg pentest auth commands instead
--chain-declared-flows test a declared cross-service @flows edge as one chained attack. Roughly 120s and one AI generation call per extra template, on partnered goals only

--fast favours speed over per-goal coverage, and its help text is explicit about when that is the wrong trade: the thorough default is for discovery, fast mode is for repeat and regression runs. A one-template goal has no partner to pair with, so --fast and --chain-declared-flows together chain only on the goals that have a declared partner to widen for.

A run that is interrupted keeps its place. Journalling is per phase, so a completed step does not re-execute.

Terminal window
bravos resume
20260818-120316-nodegoat r2 resumable
20260817-221148-nodegoat r0 interrupted — resumable
20260814-114720-bravos_observability r1 registry
20260810-214147-portainer-2.39.2 r1 model

Truncated: this machine lists 25 runs. The right-hand column is what the run can still do: resumable, interrupted — resumable, or the tier it stopped in.

Terminal window
bravos resume 20260818-120316-nodegoat

A resume keeps the --ai-provider the run started with, so the provider that generated a run’s probes does not change halfway through its ledger. Overriding it re-stamps the run’s config, and a config that has drifted since the run began is refused unless you pass --force-config-drift, because a ledger assembled under two different settings is not auditable.

bravos resume --abandon <RUN_ID> stops tracking a run and keeps its artifacts.