Skip to content

Run SAST

bravos sast run analyzes a repository with bravos-cli, the deterministic analyzer bravos setup staged. It runs Semgrep rules, request-to-sink taint over the code graph, dependency advisories with whether the vulnerable function is reached, secret scanning and IaC checks. It reads the guardlink threat model as input, so each finding is joined to the claim it supports, or listed as a lead the model is missing.

SAST is paid, with a 30-day no-card trial.

  • A licence on this machine, and the analyzer staged: bravos setup --check shows ✔ analyzer.
  • GuardLink on PATH: bravos setup --check shows ✔ guardlink · in-session probe translation. Bravos 1.5.3 checks it before starting the analyzer. If it is missing, run bravos setup --tools -y and retry.
  • Annotate first. The analyzer’s recall comes from the threat model. See Annotate a repository.
  • Build the code graph for this commit, so findings carry reach. See Ask the code graph. Without a graph the scan still runs, without reachability, and says how to add it.
Terminal window
bravos sast run --timeout 90
SAST run 20261112-065035: bravos-cli exited 0 (0 clean at the level, 1 findings, 3 licence refused or analysis failed, 4 a stage failed)

Truncated to the analyzer exit line. The parenthesis is the analyzer’s legend; this run exited 0 and still produced findings to inspect. Results are written to .bravos/sast/<run>/, which is gitignored. The full analyzer stderr remains in analyzer.stderr.log, and failures keep their diagnostic cause in the CLI output. Inspect those diagnostics before interpreting an empty candidate list. --scope and --exclude take comma-separated paths; .bravos/ is excluded.

The Bravos 1.5.3 capture uses a separate audit-notes fixture with two Flask routes, declared SQL/shell exposures and flask==2.0.1, using the signed analyzer 0.6.2 bundle. The timeout bounds this documentation check.

Terminal window
bravos sast status
SAST: 4 findings (0 reachable, 0 not in the threat model) at 9ee7e12f4, current — bravos sast candidates

The agent’s briefing and bravos watch show the same line.

Terminal window
bravos sast candidates
SAST run 20261112-065035 at 9ee7e12f4 (reachable only; --all for the rest)
Joined to a claim (0) — taint evidence for bravos-templatize and bravos-prove:
Not in the threat model yet (0) — leads for bravos-annotate:
Dependencies (0):
Secrets (0) — rotate; never pentest candidates:

By default only reachable findings are listed. This capture’s default list is empty while the run contains four findings. Reachability that is not established must remain unknown; an empty filtered list is not a clean scan.

--all adds findings whose reach is unknown or false:

Terminal window
bravos sast candidates --all
SAST run 20261112-065035 at 9ee7e12f4
Joined to a claim (2) — taint evidence for bravos-templatize and bravos-prove:
warning semgrep.python.sql.python_sql_rule-hardcoded-sql-expression app/server.py:15 [#api → #sqli at app/server.py:11]
error semgrep.python.exec.python_exec_rule-subprocess-popen-shell-true app/server.py:21 [#api → #cmdi at app/server.py:17]
Not in the threat model yet (0) — leads for bravos-annotate:
Dependencies (2):
error bravos-deps-osv-PYSEC-2023-62 requirements.txt:? vulnerable function reached: undetermined (no affected symbols)
warning bravos-deps-osv-PYSEC-2026-2151 requirements.txt:? vulnerable function reached: undetermined (core path)
Secrets (0) — rotate; never pentest candidates:

With --all, two findings join to the declared exposures and two dependency advisories appear with undetermined vulnerable-function reach. The output does not establish a live exploit or a verified control. A joined finding is taint evidence; reproduction needs a separate authorized run.

--json prints the candidates as bravos.sast-candidates/v1.

Ask “run SAST”, or run /bravos-sast. If the files in scope are unannotated, the skill runs bravos-annotate on them first. It then runs the scan and sorts the candidates: a finding joined to an open exposure goes to bravos-templatize, whose template can target its route and taint path; a reachable finding not in the model goes to bravos-annotate; an unreachable one is reported as such; a secret is reported for rotation.

bravos sast run needs a licence — it is on the Team plan: bravos account activate starts a 30-day trial (no card), or https://account.bugb.io/pricing