Home› Blog› AWS Architecture Series #64 — The guardrail's edge is written in the text it guards…
AWS Architecture AWS Architecture Series

AWS Architecture Series #64 — The guardrail's edge is written in the text it guards

Guardrails are adopted as a switch: turn them on and the application is filtered. They are not a switch, they are a boundary — and in the API that supports selective evaluation, that boundary is drawn with XML tags inside the same prompt an attacker is writing into.

Verified against current vendor documentation on 26 September 2026. Pricing, limits and API behaviour were checked against the official docs on that date. Cloud services change fast — if you are reading this much later, treat the specifics as a starting point and re-check the linked sources.

Business Challenge

#61 covered what a RAG system can find and #63 covered where the vectors live. This is the control that sits between the retrieved text and the user, and the thing worth understanding about it is not what it catches. It is where it stops looking.

Guardrails gets adopted as a checkbox — attach one, the application is filtered. The documentation describes something narrower, in three places that are easy to read past.

1Reasoning content blocks are excluded, in a parenthesis

The opening paragraph of the Guardrails documentation contains the scope, and the exclusion is inside the brackets: it protects content “that might be present in user inputs or model responses (excluding reasoning content blocks).”

On a reasoning model, the chain of thought is a content block of its own. It is generated by the model, it can contain the sensitive value the guardrail exists to mask, and it is documented as not evaluated.

That matters wherever reasoning is surfaced or logged — and it matters more since CloudWatch Omni began capturing every prompt and model call as telemetry.

Fix

Treat reasoning output as unfiltered. If it is stored or shown, it needs its own control.

2In a RAG prompt, the untagged part is the retrieved documents

Input tagging exists to save cost and latency, and AWS is direct about the consequence: “Content outside of input tags isn't processed by guardrails.”

The documented example is a RAG application: “As system prompts are provided by the developer and search results are from trusted sources, you may just need the guardrails evaluation only on the user queries.”

“Trusted sources” is doing a lot of work. In a knowledge base built from a wiki, a ticketing system or uploaded documents, the retrieved text is the least trustworthy thing in the prompt — it is where indirect prompt injection lives. Excluding it is reasonable for a curated corpus and wrong for a corpus anyone can write into.

Fix

Tag by who authored the text, not by which part of the prompt it occupies.

3Not tagging switches off the anti-injection filter

The safe-looking default is to skip tagging, and it mostly is safe: “If there are no tags in the input prompt, the complete prompt will be processed by guardrails.” Everything gets evaluated.

Except one thing. “The only exception is… prompt attack filters, which require input tags to be present.”

So Prompt Attack is a content-filter category you can configure a strength for, and it does nothing until you adopt the mechanism whose entire purpose is to exclude content from evaluation. The configuration will look correct either way.

Fix

If Prompt Attack is enabled, tag the untrusted input. Without tags it is configured and inert.

Architecture

Guardrails runs twice per call, and the two passes are not symmetrical.

Diagram: where Amazon Bedrock Guardrails evaluates, and the three documented places it does not. A request flows left to right. First the input pass: the input is evaluated against every configured policy, in parallel for improved latency, and if that evaluation results in an intervention a configured blocked message is returned and the foundation model inference is discarded entirely, so no model charges are incurred. If the input passes, the foundation model runs, and then the output pass evaluates the model response, where an intervention either replaces the response with pre-configured blocked messaging or masks the sensitive information, depending on policy configuration. The policies available are content filters covering Hate, Insults, Sexual, Violence, Misconduct and Prompt Attack with configurable strength per category, denied topics, word filters matching exact custom words and phrases, sensitive information filters that block or mask entities such as social security numbers, dates of birth and addresses and support custom regular expressions, contextual grounding checks that detect responses not grounded in the source, and automated reasoning checks that validate responses against logical rules. Three gaps are marked. First, reasoning content blocks are excluded from evaluation by documentation. Second, content outside input tags is not processed by guardrails, which in a retrieval-augmented prompt means the retrieved documents where indirect prompt injection lives, since the documented example treats search results as trusted sources. Third, prompt attack filters require input tags to be present, so omitting tags, which otherwise causes the complete prompt to be evaluated, silently disables the one filter aimed at injection. A further panel records the tag boundary itself as an attack surface: a static tag suffix lets a malicious user close the XML tag and append content after the closure, which is why AWS recommends a new random suffix on every request, limited to alphanumeric characters between 1 and 20 in length, with nesting not allowed. A closing panel records the cost asymmetry, that blocking on input avoids all model charges while blocking on output pays for the guardrail on both passes plus the inference and the response already generated.
Two passes, six policy types, and three documented places the evaluation does not reach.

The two passes, and what each one costs

On input: “the input is evaluated in parallel for each configured policy”, and on intervention “a configured blocked message response is returned and the foundation model inference is discarded.”

On output, intervention is not necessarily a block: the response “will be overridden with pre-configured blocked messaging or masking of the sensitive information based on your policy configuration.” That distinction is the whole value of the sensitive-information filter — a call-centre summary with the PII redacted is still a useful summary, where a blocked one is not.

The cost model pushes filtering to the input side

Block on input and “you're charged for the guardrail evaluation. There are no charges for foundation model inference calls.” Block on output and “you're charged for guardrail's evaluation of the input prompt and the model response… in addition to the model response that was generated before the guardrail's evaluation.” Two guardrail evaluations plus the full inference, for a response nobody sees. Catching something early is cheaper than catching it late, and the pricing says so explicitly.

The boundary is made of text, which makes it a target

Tagging works by wrapping guarded content in a reserved XML tag with a suffix you choose. AWS states the attack directly: “A static tag can result in a malicious user closing the XML tag and appending malicious content after the tag closure, resulting in an injection attack.”

Hence the guidance to “use a new, random string as the tagSuffix for every request… This helps mitigate potential prompt injection attacks by making the tag structure unpredictable” — alphanumeric, “between 1 and 20 characters”, and “Nesting of tags is not allowed.”

This is the part worth sitting with. The mechanism that decides what the filter examines is expressed inside the prompt, in the same channel as the untrusted input. A user who can guess the delimiter can write their way out of the guarded region. Randomising the suffix per request is not hardening — it is the mechanism working as designed.

Why This Architecture Holds Up

ApplyGuardrail decouples the check from the model

“Guardrails can also be used directly through the ApplyGuardrail API without invoking the foundation models.”

That is the answer to gap 1 and part of gap 2. If reasoning blocks are not evaluated in-line, and retrieved documents are excluded by your tagging, both can be passed through ApplyGuardrail as a separate step — screen a document at ingestion rather than at query time, and screen reasoning output before it is logged or displayed.

It also means the same policy can guard a non-Bedrock model, or a rules-based path, or a human-in-the-loop queue. The guardrail stops being a property of the inference call and becomes a service you call.

But the console cannot express the selective case

“The ability to evaluate only a section of the input prompt is available through the AWS SDK and not available on the management console including the Bedrock Playground and the Bedrock Guardrails management console.” So a guardrail tested in the Playground is tested against the whole prompt, while production tags a subset. The test that passes and the call that runs are evaluating different text, and nothing reports the difference. Test selective evaluation through the SDK or you are not testing what you shipped.

The filters are models, and they change under you

“Amazon Bedrock Guardrails offers a range of safeguards… that are powered by underlying models. AWS periodically updates these models to extend functionality, address new attack vectors, and strengthen safety posture. Updates apply automatically and require no action on your part.”

Read that as a dependency rather than a reassurance. Guardrail behaviour is not pinned by your guardrail version: the version fixes your configuration, not the models evaluating against it. AWS's own conclusion is the right one — “We recommend that you continue to test and validate your guardrails to confirm that they meet your requirements” — which means a regression suite, run on a schedule, not a one-off validation at launch.

The same sentence is the reason to treat detection as probabilistic in general. The sensitive-information filter is described as “probabilistic detection of sensitive information in entities such as SSN, Date of Birth, Address”, with “regular expression based detection” available for the patterns you can specify exactly. Where a format is known, the regex is the deterministic half and worth writing.

Grounding checks are the RAG-specific control

Contextual grounding “help[s] you detect hallucinations in model responses if they are not grounded (factually inaccurate or add new information) in the source or are irrelevant to the user's query.”

That is the failure #61 was about, caught at the other end of the pipeline. Chunking decides whether the answer was retrievable; grounding checks decide whether the response stayed inside what was retrieved. Neither substitutes for the other, and a RAG application with good chunking and no grounding check will still answer confidently from adjacent material.

Key Architecture Decisions

Decision Choice Reasoning
Reasoning output Treat as unfiltered Documented exclusion: "excluding reasoning content blocks".
Retrieved documents Tag them in, or screen at ingestion Untagged content is not processed, and that is where indirect injection arrives.
Prompt Attack filter Only with input tags It requires tags to be present; without them it is configured and inert.
tagSuffix Random, per request A static tag lets a user close it and append content outside the guarded region.
Where to catch Input over output An input block skips model charges entirely; an output block pays for everything.
PII handling Mask rather than block A redacted summary is still useful; a blocked one is not.
Known formats Custom regex, not just entities Entity detection is probabilistic; a regex on your own ID format is not.
Validation Scheduled, via the SDK The filter models update automatically, and the console cannot test selective evaluation.

The test worth building first

A small corpus of inputs that should be blocked, run against the real call path on a schedule — not in the Playground, and not once. The filter models change without notice, so the only thing that tells you the guardrail still does what it did last month is a suite that fails when it doesn't.

Include one case per gap: a payload that arrives inside a retrieved document, a prompt attack with tagging as production has it, and something sensitive that appears only in reasoning output. Those three are where a guardrail that looks configured is not looking.

Closing Thought

Guardrails is a genuinely good control, and every gap in this post is documented rather than hidden. That is the point. None of this requires a vulnerability report; it requires reading the page that describes the feature you turned on.

The structural observation is the third gap. A filter whose scope is declared in-band — XML tags in the same string as the user's text — has a boundary the attacker can see and, with a predictable suffix, write across. AWS documents both the risk and the mitigation in the same paragraph, which is about as fair as a vendor can be. It still means the safety of the configuration depends on a random string being regenerated on every request, forever, by code nobody will revisit.

So the question to ask about a guardrail is not whether it is enabled. It is which text it saw. On the evidence of these three pages, the answer is smaller than most teams will assume, and it is smallest exactly where the retrieved, user-supplied content lives.

Next in this series

AI & ML — Bedrock or SageMaker: consume or build. Where the line actually falls between calling a hosted model and operating your own endpoint, and which of the two decisions is reversible.

Comments

How was your experience?
Your feedback helps improve this site.
PoorExcellent