Security

When a Downstream Agent Returns Confident Garbage

Antonio Evans10 min read

A three-stage diagram: left, an agent labeled 'Producer' emits a green checkmark but the output text contains subtle errors (e.g., a date off by one year).
Key points

Key points

  1. 1Fault injection catches crashes and malformed payloads but misses outputs that are wrong yet perfectly well-formed.
  2. 2Semantic failures propagate silently because agents coordinate in natural language, which raises no runtime exception.
  3. 3A verification hop sits between the producer and the caller, checks meaning against a fixture set of known bad outputs, and applies a reject, repair or escalate rule.
  4. 4Fixtures drawn from real production failures make the hop specific, cheap to run and hard to game.

Why fault injection misses the confident answer

Fault injection tooling is built to break things loudly. The Agent Error Simulator intercepts agent-to-model HTTP traffic and injects format, logic and tool-call faults at chosen points in a planner-worker-aggregator workflow, then measures whether the workflow recovers Agent Error Simulator. That design is excellent at answering "what happens when a tool returns a 500 or a number arrives as a string". It cannot answer "what happens when the tool returns 200 with a plausible number that is wrong".

The reason is structural. Multi-agent systems coordinate in unstructured natural language rather than rigid protocols, so they are prone to semantic failures such as hallucinations, misinterpreted instructions and reasoning drift that propagate silently without raising runtime exceptions MAS-FIRE. When instructions travel as prose, there is nothing for a schema validator to reject. A JSON body that parses is treated as success.

Production teams see the same shape. Observability vendors describe agents that complete a workflow, return a response and produce output that looks correct until downstream consequences reveal the error, often hours later Latitude. One concrete example from the same taxonomy: a bad tool argument at step two silently corrupts every later step that depends on it.

A second research thread makes the case worse. A study of more than 40,000 controlled trials and 100,000 production interactions found failures occurring with static prompts, identical models and fixed databases, with no external trigger at all Silent Failure in LLM Agent Systems. These are ordering failures, not bugs, and they accumulate with interaction rounds.

The decision rule that follows is straightforward: fault injection tests the transport and the tool contract; it does not test meaning. If your only gate between agents is a schema check, you have tested the envelope and ignored the letter.

The fixture set: seeds from real bad outputs

Before you write a verifier, write down what "bad" looked like. A fixture set is a versioned file of inputs paired with the known-bad output and a label for why it is bad. It is the cheapest artifact in the whole system and the only one that keeps the hop honest.

Gather fixtures from three places:

  1. Incident tickets. Every time someone says "the agent told a customer the wrong thing", capture the request, the raw producer output and the correct answer.
  2. Reviewer overrides. When a human reviewer edits or discards an agent's draft, the discard is a fixture.
  3. Deliberate near-misses. Ask the producer model to answer questions just outside its data, then save the confident replies.

Each fixture needs a label, not just a verdict, because the label drives the routing decision later. Use a small taxonomy:

LabelWhat it looks likeTypical origin
fabricated_entityNames a record, person, order or SKU that does not existHallucinated identifier in step one of a chain
stale_factCorrect six months ago, superseded nowCached retrieval, slow index refresh
scope_creepAnswers a related question nobody askedMisread instruction in a handoff
unit_or_signRight number, wrong scale or directionArithmetic drift between worker and aggregator
truncatedEnds mid-sentence, HTTP 200, missing the second halfSilent empty or partial tool response

Store the fixture as a small record: input, producer output, label, expected behavior, and the ticket id. Keep it in the same repository as the verifier so that a change to the rule and a change to the expectation land in one review.

A useful sizing heuristic: five fixtures per label is enough to catch a regression in the verifier itself. Below that, a single edited fixture can flip a passing suite.

Designing the verification hop

The hop is a component, not a prompt. Put it in the call path, not inside the producer's instructions, so the producer cannot talk its way past it.

caller --> producer --> verification hop --> caller
                         |
                         +-- reject (return to producer with reason)
                         +-- repair (apply deterministic fix, then re-check)
                         +-- escalate (hand to human or fallback path)

The hop does four things in order, and the order matters because each step is cheaper than the next:

  1. Contract check. Does the output parse, carry every required field, and use the declared types? Structured output types are the right tool here: a framework with a typed output model forces the response to match a schema or call an output function, and validates the returned data before your code ever sees it Pydantic AI output. This step catches the loud failures that fault injection already covers. Keep it, then move on.
  2. Provenance check. For every factual claim, does a retrieved document id support it? If the producer was supposed to cite three sources and cites none, the output fails regardless of how good the prose reads. Multi-agent trust research keeps returning to this point: a downstream agent may receive instructions it cannot independently verify, and the missing control is verifiable delegation, with provenance logged at each hop multi-agent trust boundaries.
  3. Fixture check. Run the output against labelled fixtures using a judge that is deterministic where possible. Exact matching handles identifiers and numbers. For prose, use a narrow judge model with the label definitions in its instructions and a fixed rubric, not an open-ended "is this good".
  4. Rule application. Reject, repair or escalate, using the rule below.

One design constraint that is easy to miss: the hop must read the same context the caller will. An output that is wrong relative to earlier constraints in a long session looks fine in isolation, which is exactly how context loss survives review Latitude. Pass the original request, the retrieved documents and the producer's output into the hop together.

A worked reject, repair, escalate rule

The rule needs three inputs, all of which the hop already has: the label with the highest severity found, the number of repair attempts already made, and the blast radius of the action the caller is about to take.

  • Reject when the output failed the contract check or hit a fabricated_entity label. Return the failure to the producer with the specific reason and the supporting document ids it ignored. Cap retries at two. Retry loops that re-send full context burn tokens and rarely converge, which is why resilience guidance treats retry amplification as a failure in its own right Preventing Cascading Failures.
  • Repair when the fix is deterministic and safe. Normalize a unit, correct a sign against the source data, trim a truncated field, or replace an unverified name with a null and a note. Repair must be code, not a second model call, otherwise you have replaced a check with another guess.
  • Escalate when the output hit stale_fact or scope_creep, when repairs have already been applied twice, or when the caller's next action is irreversible (a payment, a deletion, an outbound message to a customer).

Worked example. A support agent drafts a refund confirmation. The producer returns: "Your refund of 4,500 USD has been approved." The hop runs:

  1. Contract: parses, has amount, currency, order_id. Pass.
  2. Provenance: order_id matches a retrieved order. The retrieved order row says 450.00 USD. Fail on the amount, label unit_or_sign.
  3. Fixture: the closest fixture is the classic off-by-100 scale error, same label. Fail.
  4. Rule: the caller is about to email the customer, so blast radius is high; the label is deterministic, so repair is allowed. The hop rewrites the amount from the order row, re-checks, and passes the corrected draft.

Total added cost: one lookup and a rule evaluation. A model call is only spent in the ambiguous branches.

The contrast is worth stating plainly. Fault injection would have reported this workflow as healthy, because every tool returned 200 and every step completed. The verification hop caught it because it compared meaning against a known-bad pattern.

Fixtures, judges and the cost of looking

A verification hop is a classifier with a cost curve. State the curve before you pick a judge, because the judge choice is the whole design.

Judge typeGood atWeak atCost per check
Exact and regex matchIdentifiers, amounts, dates, enumsParaphrase, tone, nuanceNear zero, instant
Rules over structured fieldsArithmetic, ranges, required citationsFree text without structureLow, milliseconds
Narrow judge model with rubricLabel classification, scope and driftLong inputs, borderline casesOne short model call
Human reviewerNovel cases, high-stakes callsThroughput, consistencyMinutes, expensive

Run the cheap judges first and reserve the model judge for outputs that survive them. Two details keep the judge trustworthy. First, freeze the rubric in the fixture repo and version it next to the labels, so that a change to what counts as scope_creep is reviewable. Second, measure the judge against your fixtures on a schedule: a judge that fails fixtures it used to pass is a regression, even if the producer never changed.

There is a second argument for cheap judges. Cascade failures in agent systems are expensive in a way that traditional systems are not, because every retry re-sends full conversation context and burns tokens at every step Preventing Cascading Failures. A verifier that costs a model call for every output, on top of a producer that retries twice, can double the bill of a workflow whose actual task is a single lookup. Deterministic checks first is a cost decision as much as a quality decision.

What the hop should log

The hop's logs are how you learn. Log the delegating producer, the receiving caller, the task correlation id, the label found, the rule applied and the outcome multi-agent trust boundaries. That set lets an investigator reconstruct why a downstream action was trusted.

Two derived metrics matter more than raw counts:

  • Fixture hit rate by label. A rising fabricated_entity rate after a retrieval index change is a signal, not noise.
  • Repair rate. If most outputs need repair, the producer's instructions or retrieval are broken, and the verifier is doing work the producer should be doing.

Set an alert on the second one. A verifier that repairs 40 percent of outputs is a tax on every call, and the right fix is upstream.

Where trust boundaries and policy fit

A verification hop is a trust boundary control, and it makes more sense when you see it next to its neighbours. The industry risk catalogs are explicit that compromise in one agent propagates to others through shared resources, communication channels and state corruption, with horizontal, vertical and chain-reaction patterns FINOS multi-agent trust boundaries. A verification hop is the read-side equivalent of that control: it limits what a corrupted upstream agent can do to a downstream one without being noticed.

Security guidance for agents also converges on the same three layers, which is a useful check that you have not over-built: least privilege, approval gates on high-impact actions, and monitoring behavior patterns rather than single events monday.com AI agent security. The verification hop belongs to the third layer, with a foot in the second when it escalates.

There is a plausible objection: if the verifier is a model, an attacker who can influence the producer's output can influence the verifier too. That is why the fixture check runs after the provenance check, and why deterministic judges carry the load wherever the label allows. Prompt injection remains the top risk on the OWASP list precisely because models do not reliably separate trusted instructions from untrusted content, and retrieval-augmented generation reduces but does not eliminate the exposure Prompt Injection Prevention Cheat Sheet. A judge that reads the producer's output unsupervised is a model reading untrusted content. Treat it as one.

The practical consequence: never let the verification hop call tools. It reads, compares and routes. Writing is the caller's job, after the hop returns.

Rolling it out without stalling the workflow

Start narrow. Pick the one handoff where a wrong-but-confident answer costs the most: the draft that reaches a customer, the record that updates a ledger, the summary that feeds a decision. Put the hop there first, with at least three fixtures per label, exact-match checks for every identifier and number, and escalation as the default for anything unlabeled.

Roll out in three steps that each take a day, not a quarter:

  1. Shadow mode. The hop logs its verdict and lets every output through. Compare the hop's reject rate against your incident log. If the hop flags nothing you have an incident for, the fixtures are too generic.
  2. Repair-only mode. Enable deterministic repairs. Measure the repair rate and the producer's retry count. Both should fall as instructions and retrieval get fixed.
  3. Enforce. Turn on reject and escalate for the labels you have fixtures for, and nothing else. Expand only when a new incident produces a new fixture.

Workforce readiness deserves a line because it is where these projects quietly die. Adoption of agents, not the technology, is the step that produces value, and change programs that skip it tend to leave agents without owners CIO change management. The verification hop needs a named owner, a fixture review on a fixed cadence, and one reviewer with authority to overrule the producer. That is a Friday afternoon recurring meeting, not a platform team.

Then review the whole chain once. Map every handoff, decide which ones get a hop, and record why the others do not. A written decision not to verify is a control; an unwritten one is a hope. If the chain crosses several vendors and model families, one API for text, image, audio and embeddings keeps the call path uniform, which is what makes a single verification hop practical to operate across every producer Quanta Inference.

The one thing to avoid is a verifier that only checks what is easy to check. Format and schema checks are already covered by typed output models and by fault injection. The value of the hop is entirely in the semantic checks, driven by fixtures from your own incidents. If the hops and the fixtures disagree, trust the fixtures and rewrite the hop.

FAQ

FAQ

Why not just improve the producer prompt instead of adding a verification hop?

Prompts help, but silent failures occur under static prompts and fixed models, with no external trigger Silent Failure in LLM Agent Systems. A prompt is an instruction; a hop is a control that runs after the producer has finished and cannot be argued with. Use both, but never treat the first as the second.

How many fixtures do I need before the hop is worth running?

Start with five per label across three labels, drawn from real incident tickets and reviewer overrides. The immediate goal is not coverage of every possible failure, it is a suite sensitive enough that a change to the verifier shows up as a test result. Expand whenever a new incident produces a new label.

Should the verifier be the same model as the producer?

No. A verifier built on the same model tends to share the producer's blind spots, and model-specific arithmetic deficits interact with injected faults in non-obvious ways Agent Error Simulator. Prefer deterministic checks first, then a different model with a frozen rubric for the residue.

Does a verification hop slow every call down?

The cheap checks (contract, identifier matching, rule evaluation) run in milliseconds. Only ambiguous outputs pay for a model judge, and only escalations pay for a human. Measure the judge rate before enabling enforcement, and keep the escalate threshold tight.

What is the minimum I should log from the hop?

Producer id, caller id, task correlation id, label found, rule applied and outcome. That tuple is enough to reconstruct why an action was trusted, and it is the same provenance pattern trust boundary guidance recommends for inter-agent delegation multi-agent trust boundaries. Add the retrieved document ids used by the provenance check.

Sources

Sources

  1. Agent Error Simulator: Fault Injection for Testing Recovery in ...
  2. MAS-FIRE: Fault Injection and Reliability Evaluation for ...
  3. Detecting AI agent failure modes in production - Latitude.so
  4. Silent Failure in LLM Agent Systems: The Entropy Principle ...
  5. Output | Pydantic Docs
  6. Multi-agent trust boundaries in AI systems: what breaks first?
  7. Preventing Cascading Failures in AI Agents
  8. Multi-Agent Trust Boundary Violations
  9. AI Agent Security: Controls, Risks, and Best Practices
  10. LLM Prompt Injection Prevention Cheat Sheet
  11. Preparing your workforce for AI agents: A change ... - CIO
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles