Skip to content

Lenses

A lens is the perspective a round works from. It decides what the agent looks for when it annotates, and which identity the probes run as. Bravos ships six, and rotates through them.

Six perspectives are not six times the work for its own sake. The same line of code is a different threat depending on who is standing in front of it, and a tool that only ever asks one of those questions returns a confident, partial answer.

Read straight from the command’s own help:

--lens LENS perspective to annotate from (admin, chained,
crosstenant, mitigation-audit, stduser, unauth)
Lens Asks
unauth what does an anonymous request reach?
mitigation-audit do the declared controls actually hold?
stduser what does an ordinary logged-in user reach?
crosstenant what does one user reach of another’s?
admin what does a privileged account reach, and should it?
chained what becomes reachable once something else is proven?

Round 1 is always unauth. It needs no identities, so a broken environment fails there, in the cheapest round, rather than three rounds in, after the agent budget is spent.

mitigation-audit is scheduled second, and that is the choice worth explaining.

A single @mitigates removes every exposure sharing its asset/threat pair from guardlink’s SARIF export. cxg never sees them, so no probe can be generated for them, so nothing can ever confirm or refute them. A control that is 90% correct is therefore more dangerous than no control at all: it silently ends the investigation into everything it claims to cover.

One annotation is enough to do it, and bravos inspect is what tells you it happened. On the small repository from Build your first threat model, a single @mitigates removed one exposure from the export:

SUPPRESSED FROM EXPORT (1)
A @mitigates or @accepts anywhere in the repo removes every exposure sharing that
pair from the SARIF export. cxg never sees these and cannot test them.
high orders::xss ×1 via @mitigates

The count scales with how many exposures share the pair, not with how many annotations were written: one @mitigates over a pair with four exposures removes four.

mitigation-audit is the lens that restates those exposures into the export so cxg can attack the control instead of assuming it. Asking “does the declared control actually hold” is what a @mitigates otherwise stops anyone from asking.

crosstenant asks whether one user reaches another’s data. With one identity captured, the question is unanswerable, and the round produces nothing: not a refutation, and not a clean result either.

So the environment decides which lenses are real. Two equal-privilege identities plus one privileged identity is the shape most lenses assume; the environment guide captures them.

A run records per-lens counters: attempts, uses, new exposures, confirmed findings, consecutive dry rounds, and whether the lens is retired, with a reason. A lens that stops producing is retired, and a run whose lenses are all retired has stopped for a stated reason rather than a budget one.

You can also pin one:

Terminal window
bravos annotate . --lens mitigation-audit
bravos round . --lens crosstenant --target http://127.0.0.1:9054

--focus narrows a lens further in your own words. Per its own help, it narrows the lens and cannot relax the rules.

  • Every lens is another annotate phase, and annotation is an agent call against the whole repository.
  • Lenses overlap. stduser and crosstenant will both re-derive some of the same exposures; the ledger deduplicates the threats, not the work of finding them.
  • A lens can be wasted. A round under a lens whose identities are missing costs an agent call and returns nothing, and it will not tell you in advance.