Blog// LOG 011

Mandiant AVDH: Build a Skeptical Validation Harness

Mandiant's AVDH forces AI findings through threat modelling, binary exploit oracles and human review. Rebuild the validation loop in Python.

7 MINUTE READ

Short answer: Mandiant’s Agentic Vulnerability Discovery Harness (AVDH) works because models are allowed to generate broad hypotheses inside a deterministic process. Threat modelling, reachability checks, independent validation, exploit replay and human review decide what becomes a finding. The model proposes. The harness has to prove.

Authorised-use notice: Run the companion code only on local synthetic cases or systems you own and are authorised to test. The included command-injection oracle executes a harmless marker on the local host. It is a teaching check, not a production scanner.

On 18 August 2026, Mandiant published the internal architecture of AVDH. The headline result deserves attention: during one incident-response engagement, Mandiant says the system found more than 100 true-positive critical vulnerabilities in two days. Across ten months, the team reports thousands of pipelines, tens of thousands of findings and 12 assigned CVEs. Two named examples, CVE-2026-13242 and CVE-2026-55803, have public Drupal advisories. Those figures are Mandiant’s reported production results, not results reproduced in this article.

The result worth copying is the architecture. AVDH gives stochastic models room to explore, then surrounds them with fixed gates that refuse to confuse a plausible story with an exploitable flaw. That pattern can improve an AppSec workflow even when the frontier model, agent framework and budget all change.

Six candidate vulnerability hypotheses move through a threat-model gate and binary exploit oracle. Two are rejected, two are disproven, and two reach human expert review.
Original reconstruction of the control flow tested in this article. It is inspired by Mandiant’s disclosed AVDH pipeline, not a copy of Mandiant’s internal diagrams.

What Mandiant AVDH actually does

AVDH starts with a threat model. Explorer agents identify the application’s purpose, attack surface, authentication and authorisation boundaries, routes and out-of-scope directories. A consultant reviews the resulting model before the pipeline continues. That approval gate matters because a perfect sink detector still wastes time when the sink sits in dead code or behind a boundary the assumed attacker cannot cross.

The next stages discover entry points, collect distributed context and generate hypotheses about access control and data flow. Mandiant deliberately separates generation from validation. Multiple high-temperature validators challenge each hypothesis, a synthesis agent assigns one of three outcomes, and a human consultant finally reproduces the exploit. Findings that fail dynamic testing are discarded.

Stage Question Failure it prevents
Threat model Who can reach this code, and with which trust? Reporting dead, test-only or admin-only paths as public flaws
Entry-point discovery Where does attacker-controlled input enter? Scanning files without an attack path
Context enrichment Which checks and transformations sit between source and sink? Missing sanitisation or permission checks in another file
Hypothesis generation What could be exploitable? Narrow rules that only catch familiar syntax
Validation Which evidence contradicts the claim? A fluent model agreeing with its own first answer
Expert replay Can the impact be reproduced under the threat model? Publishing an unverified vulnerability

Mandiant implemented the orchestration with Google’s Agent Development Kit. ADK can be swapped out. The stage contract cannot. The security boundary lives in the evidence each stage must produce before the next one runs.

A six-case reproduction of the validation shape

The companion harness strips the idea down to 113 lines of Python and six hand-built synthetic cases. It contains no LLM and makes no claim about model quality. The candidate generator deliberately over-reports every case so the validation stages have something noisy to clean up. This makes the control flow easy to inspect.

python mini_avdh_harness.py

candidate hypotheses: 6
confirmed:             2
disproven:             2
rejected by scope:     2
precision before gate: 0.333
precision after gate:  1.000

The two confirmed cases are a shell-string concatenation that executes a harmless marker and an invoice endpoint that returns Alice’s record to Bob. A strict allowlist blocks the matching shell payload in a second case. An ownership check blocks the matching invoice request in another. The threat-model gate rejects an admin-only maintenance command and dead debug code before any payload runs.

So the deliberately noisy candidate set starts at two correct claims out of six, or 33.3% precision. The validation gate forwards two confirmed claims out of two, or 100% precision on this tiny benchmark. That is a pipeline sanity check, not evidence that the method will achieve 100% precision on a real repository. Six synthetic cases cannot measure recall, language coverage, architectural reasoning or resistance to adversarial source code.

def validate(hypothesis):
    if hypothesis.exposure != "public":
        return "rejected"

    impact_reproduced = hypothesis.oracle()
    return "confirmed" if impact_reproduced else "disproven"

Five lines carry the core constraint: model confidence never appears in the final decision. Exposure comes from the reviewed threat model. Impact comes from a deterministic oracle. For a memory-safety bug, that oracle might be a crash under AddressSanitizer. For command injection, it can be a marker written by a harmless payload. An authorisation flaw needs a policy assertion: principal B obtained object A despite an explicit ownership rule.

Download the companion Python harness and its recorded result. The output is also preserved as part of today’s publication artefacts.

Binary oracles have a narrow sweet spot

Mandiant’s July guidance on AI-assisted vulnerability management separates binary oracles from architectural ones. A crash, leaked marker or unauthorised response gives a machine a crisp pass or fail. Business-logic flaws, indirect SSRF and cross-service trust failures often depend on intent that is absent from the repository. A failed payload could mean the hypothesis is wrong, the payload is malformed or a compensating control blocked only this attempt.

Deploy agentic review first where the system can observe a trustworthy outcome. Keep a human threat modeller in the loop when the proof depends on business ownership, data sensitivity or unwritten trust. If the oracle depends on business intent, label it architectural and keep the decision with a reviewer.

Write the oracle before accepting the finding

A useful finding contract can fit in one record:

{
  "entry_point": "POST /invoices/{id}",
  "attacker": "authenticated user without ownership",
  "precondition": "invoice belongs to another tenant",
  "payload": "GET /invoices/ACME-1042",
  "oracle": "response status is 200 and body contains ACME data",
  "evidence": "test output plus request and response hashes",
  "human_approval": null
}

The null approval is intentional. Discovery can continue, but publication, ticket closure and code merge must wait. This mirrors the method used in the existing Pickle Rick attack-path reconstruction, where representative output is labelled and the decision behind each command stays beside the command.

Treat the repository as hostile input

An AI reviewer reads comments, documentation, test fixtures and dependencies. Any of them can contain instructions aimed at the model. Mandiant’s operational guidance explicitly treats source code as untrusted input because an attacker can plant indirect prompt injection in comments or third-party packages. OWASP’s prompt-injection guidance reaches the same control: segregate external content, validate output formats with deterministic code, minimise privileges and require human approval for high-risk actions.

A code-review agent therefore needs two sandboxes. The first limits what analysed code can do when built or tested. The second limits what the agent can do if repository text changes its behaviour. A practical runner should use a disposable container, synthetic data, no production network route, no ambient cloud credentials and a short-lived token bound to one repository and branch.

Control Minimum implementation Evidence to retain
Isolation Ephemeral, unprivileged container with a read-only source mount Image digest and sandbox policy
Egress Deny by default; allow only pinned model and package endpoints Network policy and connection log
Identity Short-lived repository token with pull-request scope Token audience, branch and expiry
Validation Regression suite plus vulnerability-specific oracle Exit code, logs and artefact hashes
Decision Named human approves disclosure or merge Reviewer identity and timestamp

A build order that keeps the harness honest

  1. Start with ten synthetic cases. Mix reachable vulnerabilities, safe lookalikes and dead paths. Manually verify every expected outcome.
  2. Define the threat-model schema. Record attacker identity, entry points, trust boundaries, data assets and explicit exclusions.
  3. Require structured hypotheses. Every claim needs a source, sink, path, precondition and proposed oracle. Reject free-form findings at the interface.
  4. Separate generation from challenge. The component that proposed a flaw should not be the only component judging it.
  5. Run proof in a disposable environment. Capture inputs, outputs, exit codes and hashes. Destroy the environment after the run.
  6. Grade against exact ground truth. Count duplicates once. Investigate unmatched findings instead of silently labelling all of them false positives.
  7. Hold the final gate. A person reproduces confirmed impact and approves the risk statement before disclosure or remediation.

Mandiant’s published results show that agentic code review can operate beyond a toy demo. The disclosed architecture explains the result: creative model behaviour runs inside a process that is sceptical by design. Faster models will produce more hypotheses. The teams that benefit will be the ones whose gates discard bad evidence at the same speed.

Sources and further practice