Placement in the loop — and how catalogs fail
Lesson 4 of 5 in The Guardrail Catalog: Runtime Checks, Mapped Per Cloud.
A catalog is a list; a defence is a placement. Walk the agent loop and put each entry where it can actually see the data it is meant to judge.
The diagram below is the canonical arrangement. Click through the nodes: the two easiest points to forget are tool-response checks — where indirect injection and poisoned tool output arrive — and the sanitise-before-render step at the very end, which is where the exfiltration channel closes.
Where each check sits in the agent loop
- Request enters the loop
A user message, a scheduled trigger, or an inbound event. Whatever the source, it is data — not authority.
- Input checks — pass?
Catalog rows 1–3: injection heuristics, PII detection, topic bounds. Cheap and early, but structurally blind to anything the agent will later retrieve.
- Refuse, log, and count it
Log every block with check id, score and trace pointer. Blocks are your only early-warning signal that someone is probing you — a refusal you do not count is a refusal you cannot learn from.
- Model reasons over context
The one box in this diagram you cannot put a guardrail inside. Everything the model reads — including tool results — is treated as potentially instruction-bearing.
- Tool call or final answer?
Model-directed control flow. Nothing in your code chose this branch, which is exactly why both outgoing paths need checks.
- Tool-call checks — allow, gate, or deny?
Catalog rows 4 and 6: deterministic schema, range and allowlist validation first (free, exact), then a sensitive-action classifier that routes high-consequence calls to an approval gate. This is the highest-value placement in the loop.
- Execute inside containment
Least-privilege credential, sandboxed process, egress allowlist, session budget. The layer that holds when every check above it missed.
- Tool-response checks
Catalog rows 1 and 2 again, plus a size cap. The most commonly missing placement in home-grown stacks — and the one indirect prompt injection depends on. Foundry models it explicitly as the "tool response" intervention point.
- Output checks
Catalog rows 2, 3 and 5: PII masking, topic bounds, grounding against the retrieved sources. Expensive, so scope it to answers people act on.
- Sanitise before rendering
Catalog row 8. Strip auto-fetching markup — images, forms, iframes, CSS url(), link previews — in every channel that renders model output. Free, deterministic, and the fix behind most published agent-exfiltration patches.
- Render to the user
Now the uncomfortable half of the lesson. Catalogs fail in predictable ways, and none of the failures look like a security incident while they are happening — they look like a latency complaint, a support ticket, or a slide in a compliance review.
Guardrail latency — the loop multiplies your check budget
A single check that adds 300 ms sounds harmless. Now count properly: an agent run with twelve loop iterations pays your tool-response check twelve times. Add an input check, an output check, and a grounding call and you have added seconds to a single answer, most of it invisible in a per-call benchmark.
Three fixes, in order of impact. Run checks in parallel where they are independent rather than chaining them serially. Put the cheap deterministic checks first and short-circuit — schema validation costs microseconds and rejects a class of calls before any classifier runs. And scope the expensive ones: grounding on the final answer, not on every intermediate step.
The failure mode to watch for is not slowness itself. It is the pull request six weeks later titled “disable grounding check for latency”, merged without a security review.
False-positive fatigue — the tax is paid in human attention
A sensitive-action classifier firing on 30% of legitimate calls does not make the system 30% safer. It trains reviewers to approve without reading, and it trains engineers to add bypass flags. Both convert your guardrail into latency with extra steps.
Measure the false-positive rate per entry as a first-class metric, alongside detection. Then treat a rising rate as an incident of its own: tune the threshold, narrow the scope, or replace the classifier with a deterministic rule that cannot be wrong. And watch review time — a gate whose median approval latency has fallen to three seconds is not a gate any more, whatever the architecture diagram says.
The “guardrail theatre” trap — a catalog that protects the audit, not the agent
Theatre has a recognisable smell. Twelve guardrail entries, all at user input, none at tool response. Content filters enabled on an agent whose real risk is an over-scoped database credential. A shiny per-check dashboard and no test fixtures, so nobody knows the current detection rate. A completed control matrix on an agent with unrestricted network egress.
The diagnostic question is brutal and short: name the last attack this specific entry would have stopped, and show me the test that proves it still would. If the answer is a vendor feature list, you have theatre.
The structural cause is that guardrails are legible — they have names, dashboards and vendor logos — while containment is boring: a narrower IAM role, a shorter egress allowlist. Legibility attracts budget. Boring saves you.
Silent fail-open — the check that stopped working in March
Classifier endpoints throttle, time out, and get deprecated. If your default on error is “let it through and log”, and nobody alerts on the log, your catalog now documents a control you no longer have.
Declare the fail mode per entry, alert on check-error rates (not just on blocks), and re-run the fixtures on every model, prompt, threshold and provider change. Model upgrades are the single most common cause of a silently degraded guardrail: same code, same config, different detection rate. This is precisely why guardrail fixtures belong in the CI regression suite next to your quality evals.
Double-counted coverage — one control claimed by three layers
A team maps “prompt injection” to the model’s safety training, the platform content filter, and a home-grown heuristic, then rates the risk as triple-covered. In reality all three are classifiers with correlated blind spots: the payload that reads as innocuous prose to one often reads that way to the others.
Correlated detectors do not stack like independent controls. Coverage counting is only honest when the layers fail for different reasons — a classifier plus a read-only credential plus an egress allowlist really is three layers, because two of them recognise nothing at all.
Place the check: which intervention point does this entry belong at?
Interactive decision tree — outcomes:
- Output sanitisation, at every rendering boundary
Catalog row 8. Strip auto-fetching markup before render — and remember that “render” happens in more places than your main UI: emails, PR comments, chat messages, link previews. Free, deterministic, and the fix behind most published agent-exfiltration patches. Lesson 5 works it end to end.
- Both user input and tool response
The correct answer for injection heuristics, and the placement Microsoft Foundry’s Prompt Shields encodes for document attacks. Wiring it to user input alone leaves the indirect-injection path — the one every published exfiltration chain used — completely unwatched. On Foundry, confirm the tool-response half actually fires: that intervention point requires moderation support from the tool, and Microsoft publishes the supported-tool list, so a custom or third-party tool is unscanned even when the control is configured.
- User input only
Fine for genuinely user-shaped risks: jailbreak framing, off-scope requests, PII the user volunteers. Cheapest placement in the loop. Just re-ask the question every time you add a retrieval tool, because new context sources change the answer.
- Tool response — before the content reaches the model
Catalog rows 1 and 2 at the point most home-grown stacks miss. Cap the size too: an unbounded tool result is both a context-flooding vector and a bill. Note it runs once per loop iteration, so keep it cheap or you will pay for it a dozen times per run.
- Output — a grounding check against the sources
Catalog row 5, and the most expensive entry in the catalog: a second model call plus the source tokens. Worth it on answers people act on; wasteful on intermediate steps. Bedrock exposes this as contextual grounding checks; on the other two clouds grounding currently lives on the evaluation side.
- Tool call — deterministic validation
Best outcome in this tree. Microseconds, no false positives, no model call, no drift on model upgrades. Put it in the tool implementation and, if your platform offers a chokepoint, at the gateway — AgentCore Policy expresses exactly this as Cedar rules evaluated on every action through AgentCore Gateway.
- Tool call — classifier, failing closed
Acceptable for consequence judgements that resist deterministic rules. Two obligations: fail closed on high-consequence actions (you chose correctly), and watch the false-positive rate, because every false positive spends reviewer attention you cannot buy more of.
- Fail-open on a high-consequence action
This is the silent-failure pattern. An attacker who can make your classifier time out has just disabled the control, and the only trace is a log line nobody alerts on. Fail closed here, or express the rule deterministically so it cannot time out in the first place.
Tool: Prompt Injection Range — Take a catalog into the Injection Range and watch which entries hold: the payloads that slip past an input-only filter are the same ones that walk straight into a tool-response check.
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.