Skip to main content
Every findings[] entry in scan.json is a one-attack record with enough context to replay the attack, audit the verdict, and route to a fix. Source of truth: models/finding.py

When to use this page

  • You opened a finding in scan.json and want to know what every field means before you triage it.
  • You’re writing a parser that walks scan.json and needs to know which fields are guaranteed present vs nullable.
  • You want to replay a finding deterministically (the PoV gate output
    • trigger_prompt).

The finding shape

The fields fall into four groups: identity, mapping, verdict, and evidence.

Identity

A single probe can produce multiple findings on one scan (one per landed turn). probe_id is your group-by key.

Mapping (the OWASP / MITRE / CSA triple)

Every finding carries the same triple, inherited from the probe YAML. The triple-framework gate in models/probe.py:_coerce_probe enforces that all three are populated before a probe loads. The triple is the same triple every emitter carries — SARIF rules[].properties.asi / properties.mitre_atlas / properties.csa, JUnit <system-out> tags, Markdown’s per-finding header. Cross-emitter consistency is asserted by the canonical schema.

Verdict

success=true is what the AIVSS penalty counts (and what the high-severity band cap fires on). A finding emitted with success=false is recorded for trend tracking but does not penalise the score.

Evidence + replay

The replay contract

trigger_prompt is deliberately sufficient to replay the attack against the same target — no hidden state, no extra config. The PoV runner does exactly that: rerun trigger_prompt N times under the same target adapter and report the success rate.
The PoV gate (--pov-gate) runs this automatically before scoring and drops findings whose reliability falls below the gate threshold so the score never reflects a one-in-twenty flake.

Redaction (always on)

PII and credential redaction is on by default for every emitter. The shared redact_finding helper scrubs five fields before serialisation:
  • summary
  • description (probe-level; carried into the SARIF rule)
  • trigger_prompt
  • transcript_ref (the path string, in case it embeds an identifier)
  • evidence payload bytes (the contents of transcript_ref)
The regex fallback catches OpenAI / AWS / GitHub / Google API key shapes, JWTs, bearer tokens, and password= assignments. Install agent-guardian[full] to layer presidio on top for richer PII (names, phone numbers, emails). This isn’t a knob — a security scanner must never re-emit a captured secret.

What the bundle directory looks like

--bundle ./out/ emits a checksummed tree alongside the JSON report:
The manifest.json carries SHA-256 + byte count for every file plus the scan envelope (id, AIVSS, band, formula version). This is the artifact you archive for audit — see reports/bundle.py.

Walking findings in code

The minimal idiom — group by ASI category, surface the critical-band findings first:
This matches the order the Markdown emitter uses for its top-5 table.

Next step

AIVSS score

The five-step pipeline + the mode_authoritative rule that gates --fail-under.

Severity levels

The four severity tiers + how each contributes to the headline.

Report schema

Field-by-field reference for agentguardian-scan-v1.

JSON export

Sample scan.json end-to-end + the canonical-form rules.