Bedrock Guardrails
Bedrock Guardrails is the managed safety layer that sits between user input and model output. A guardrail is a versioned, IAM-controlled resource that combines six configurable filter types — content filters, denied topics, word filters, sensitive-info filters (PII), contextual grounding checks, and automated reasoning checks — and runs them on both the prompt and the completion. Apply it to any Bedrock model via the guardrailConfig field on Converse / InvokeModel, attach it to a Bedrock Agent, or use it standalone via the ApplyGuardrail API to evaluate text that hasn’t been through Bedrock at all (useful for filtering third-party model output).
See also
- bedrock-api-and-converse — the
guardrailConfigfield on Converse requests - bedrock-agents — agents can be attached to a guardrail
- bedrock-knowledge-bases-rag —
RetrieveAndGenerateaccepts a guardrail config - auth-authz — IAM control plane that gates guardrail creation and use
1. The six filter types
Per docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html.
| Filter | What it does | Configurable severity |
|---|---|---|
| Content filters | Detect and block six harm categories: Hate, Insults, Sexual, Violence, Misconduct, Prompt Attack | NONE / LOW / MEDIUM / HIGH per category, per input/output |
| Denied topics | User-defined topics that should be off-limits (“legal advice”, “financial advice”, “competitor X”) | Per-topic on/off, with name + definition + example phrases |
| Word filters | Exact-match blocklist of words and phrases. Includes built-in profanity list. | Per-word on/off |
| Sensitive info filters (PII) | Detect and block or mask PII (SSN, credit card, address, phone, email, IP, custom regex). 30+ entity types. | BLOCK / ANONYMIZE per entity type |
| Contextual grounding check | Detect hallucinations — measures grounding (response uses source) and relevance (response addresses query) | Threshold 0.0–0.99 per metric |
| Automated Reasoning checks | Formal logical validation against rules expressed in a custom policy domain | Policy + ARN |
2. Tiers — Classic vs Standard
Per re:Invent 2024: Bedrock Guardrails now has two tiers.
- Classic (legacy, cheaper) — text-only filtering, English-only for content filters, no code-aware filtering.
- Standard — adds image content filtering, code-aware filtering (detects harmful intent inside code comments + string literals + variable names), expanded language coverage.
Pricing:
- Classic: $0.15 per 1,000 text units (1 text unit = 1k chars input).
- Standard: $0.20 per 1,000 text units for content + denied topics, $0.10 / 1k for PII detection, $0.50 / 1k for PII detection + redaction, $0.10 / 1k for contextual grounding checks.
3. Creating a guardrail — Python walkthrough
import boto3
ctl = boto3.client("bedrock", region_name="us-east-1")
resp = ctl.create_guardrail(
name="prod-customer-chat-guard",
description="Block harmful content + competitor mentions + financial advice",
blockedInputMessaging="I can't help with that. Try rephrasing.",
blockedOutputsMessaging="I'm not able to provide that information.",
# 1. Content filters
contentPolicyConfig={
"filtersConfig": [
{"type": "SEXUAL", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "VIOLENCE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "HATE", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "INSULTS", "inputStrength": "MEDIUM", "outputStrength": "MEDIUM"},
{"type": "MISCONDUCT", "inputStrength": "HIGH", "outputStrength": "HIGH"},
{"type": "PROMPT_ATTACK", "inputStrength": "HIGH", "outputStrength": "NONE"},
]
},
# 2. Denied topics
topicPolicyConfig={
"topicsConfig": [
{
"name": "FinancialAdvice",
"definition": (
"Investment advice, stock recommendations, or specific "
"guidance on buying/selling financial instruments."
),
"examples": [
"Should I buy AAPL?",
"What's a good ETF to invest in?",
],
"type": "DENY",
},
{
"name": "Competitors",
"definition": "Discussion of competing products by name",
"examples": ["What about Acme Corp's offering?"],
"type": "DENY",
},
]
},
# 3. Word filters
wordPolicyConfig={
"wordsConfig": [{"text": "internal-codename-x"}],
"managedWordListsConfig": [{"type": "PROFANITY"}],
},
# 4. Sensitive info / PII
sensitiveInformationPolicyConfig={
"piiEntitiesConfig": [
{"type": "EMAIL", "action": "ANONYMIZE"},
{"type": "PHONE", "action": "ANONYMIZE"},
{"type": "CREDIT_DEBIT_CARD_NUMBER", "action": "BLOCK"},
{"type": "US_SOCIAL_SECURITY_NUMBER", "action": "BLOCK"},
{"type": "IP_ADDRESS", "action": "ANONYMIZE"},
],
"regexesConfig": [
{
"name": "InternalEmployeeID",
"pattern": r"EMP-\d{6}",
"action": "ANONYMIZE",
}
],
},
# 5. Contextual grounding (for RAG)
contextualGroundingPolicyConfig={
"filtersConfig": [
{"type": "GROUNDING", "threshold": 0.7},
{"type": "RELEVANCE", "threshold": 0.5},
]
},
tags=[{"key": "Environment", "value": "production"}],
)
guardrail_id = resp["guardrailId"]
# Create a version (immutable snapshot)
v = ctl.create_guardrail_version(
guardrailIdentifier=guardrail_id,
description="Initial production version",
)
print(f"Version: {v['version']}")4. Applying a guardrail at inference time
Via Converse
runtime = boto3.client("bedrock-runtime", region_name="us-east-1")
resp = runtime.converse(
modelId="anthropic.claude-sonnet-4-6-20260119-v1:0",
messages=[{"role": "user", "content": [{"text": "Should I buy Tesla stock?"}]}],
guardrailConfig={
"guardrailIdentifier": guardrail_id,
"guardrailVersion": "1",
"trace": "enabled", # include guardrail trace in response
},
)
if resp["stopReason"] == "guardrail_intervened":
print("Guardrail blocked. Filters that fired:")
for filt in resp["trace"]["guardrail"]["inputAssessment"][guardrail_id]["topicPolicy"]["topics"]:
if filt["action"] == "BLOCKED":
print(f" - Topic: {filt['name']}")Selective content evaluation
By default the guardrail evaluates every message. If you have safe RAG context that shouldn’t be re-evaluated as user input, mark only the actual user query:
"messages": [{
"role": "user",
"content": [
{"text": "Context: <KB results>"},
{
"guardContent": {
"text": {"text": "User question here"}
}
},
],
}]Only the guardContent-wrapped block is evaluated.
Standalone ApplyGuardrail
Apply a guardrail to text that didn’t go through Bedrock — useful for filtering output from a third-party model:
resp = runtime.apply_guardrail(
guardrailIdentifier=guardrail_id,
guardrailVersion="1",
source="OUTPUT", # or "INPUT"
content=[{"text": {"text": "The text to evaluate"}}],
)
# Inspect action: NONE / GUARDRAIL_INTERVENED
print(resp["action"])
print(resp["outputs"]) # potentially modified text
print(resp["assessments"]) # detailed filter results5. Contextual grounding — the RAG hallucination filter
Per docs.aws.amazon.com/bedrock/latest/userguide/guardrails-contextual-grounding-check.html.
Two metrics, each scored 0.0–1.0:
- Grounding — does the response only use information from the provided source?
- Relevance — does the response address the user’s query?
Configured with thresholds. If the score is below threshold, the response is blocked (or annotated, depending on action). Typically used in RetrieveAndGenerate flows:
# At inference time, pass the source text via guardContent qualifier
"messages": [{
"role": "user",
"content": [
{
"guardContent": {
"text": {
"text": "[long KB context here]",
"qualifiers": ["grounding_source"], # ← tells guardrail this is source-of-truth
}
}
},
{
"guardContent": {
"text": {
"text": "What is the parental leave policy?",
"qualifiers": ["query"],
}
}
},
],
}]The guardrail then evaluates the model’s response against the marked source. Grounding score < 0.7 = likely hallucination.
6. Automated Reasoning checks (re:Invent 2024)
Per docs.aws.amazon.com/bedrock/latest/userguide/automated-reasoning-checks.html. This is a formal verification layer — you define logical rules in a custom “policy domain” (e.g. “patients on warfarin should not take ibuprofen”), and Bedrock uses an automated reasoning engine to verify model output against those rules.
Status: GA in 2025, but takes meaningful setup — you author the policy in Bedrock’s policy authoring console, train it against examples, then attach to the guardrail. Useful in regulated domains (healthcare, finance, legal) where you can express ground truth as logical rules.
# Once the policy is authored and trained:
ctl.update_guardrail(
guardrailIdentifier=guardrail_id,
automatedReasoningPolicyConfig={
"policies": ["arn:aws:bedrock:us-east-1:...:automated-reasoning-policy/abc"],
"confidenceThreshold": 0.85,
},
# ... other config remains
)7. Sensitive info / PII — entity list
Per docs.aws.amazon.com/bedrock/latest/userguide/guardrails-sensitive-information-filters.html. 30+ entity types organized by category:
General:
ADDRESS, AGE, NAME, EMAIL, PHONE, USERNAME, PASSWORD, DRIVER_ID, LICENSE_PLATE, VEHICLE_IDENTIFICATION_NUMBER
Financial:
CREDIT_DEBIT_CARD_NUMBER, CREDIT_DEBIT_CARD_CVV, CREDIT_DEBIT_CARD_EXPIRY, PIN, INTERNATIONAL_BANK_ACCOUNT_NUMBER, SWIFT_CODE
Identifiers (US):
US_BANK_ACCOUNT_NUMBER, US_BANK_ROUTING_NUMBER, US_INDIVIDUAL_TAX_IDENTIFICATION_NUMBER, US_PASSPORT_NUMBER, US_SOCIAL_SECURITY_NUMBER
Identifiers (other):
UK_NATIONAL_HEALTH_SERVICE_NUMBER, UK_NATIONAL_INSURANCE_NUMBER, UK_UNIQUE_TAXPAYER_REFERENCE_NUMBER, CA_HEALTH_NUMBER, CA_SOCIAL_INSURANCE_NUMBER
Tech:
URL, IP_ADDRESS, MAC_ADDRESS, AWS_ACCESS_KEY, AWS_SECRET_KEY
Per-entity action options:
BLOCK— entire request/response is blocked.ANONYMIZE— entity is replaced with[EMAIL],[SSN], etc.
Custom regex patterns also supported (see config example above).
8. Cross-region distribution
Per docs.aws.amazon.com/bedrock/latest/userguide/guardrails-cross-region.html. A guardrail in us-east-1 can be invoked from other regions via a system-defined cross-region inference profile. Useful when your application traffic is multi-region but you want a single guardrail policy.
9. Inspecting traces
When trace: "enabled" is set on guardrailConfig, the response includes a detailed assessment showing which filters fired:
trace = resp["trace"]["guardrail"]
# trace.inputAssessment.<guardrail_id>.{contentPolicy, topicPolicy, wordPolicy, sensitiveInformationPolicy, contextualGroundingPolicy}
# Each filter has confidence scores, matched values, and actions takenFor production, write traces to CloudWatch — they’re invaluable for tuning thresholds and explaining blocks to users.
10. Limits and quirks
| Limit | Value |
|---|---|
| Max guardrails per account per region | 100 |
| Max versions per guardrail | 20 |
| Max denied topics per guardrail | 30 |
| Max words in custom blocklist | 10,000 |
| Max length per word/phrase | 200 chars |
| Max custom regex patterns | 10 |
| Max input size per call | 25 KB |
| Latency overhead | ~80-200ms per evaluation (input + output) |
Quirks:
- Guardrail latency is serial with model inference — the guardrail evaluates input before the model runs and output after it completes. For streaming responses, the guardrail buffers the stream and evaluates it in chunks, so streamed output is slightly delayed vs an un-guardrailed stream.
- Reasoning content blocks are NOT evaluated (per the docs page). If you use Claude extended thinking, the model’s reasoning can contain harmful content that’s not caught. Strip reasoning content from anything you log or expose.
- Built-in PII detection is probabilistic — works well on common formats (US-style SSN, common credit card patterns) but misses unusual formats. Add custom regex for org-specific identifiers.
- Cross-account guardrails (re:Invent 2024) — a central security team can publish a guardrail in account A, and accounts B/C/D can use it via cross-account permissions. Useful for compliance-driven shared safety policies.
11. When to use Guardrails vs DIY
Use Bedrock Guardrails when:
- You’re already on Bedrock and want a managed, IAM-controlled safety layer.
- You need PII detection + redaction without writing your own detectors.
- You want versioned policies that auditors can inspect.
- Contextual grounding for RAG hallucination detection is appealing.
DIY (open-source like Llama Guard or NVIDIA NeMo Guardrails) when:
- You’re calling third-party models that aren’t on Bedrock (and don’t want to use
ApplyGuardrailoverhead). - You need filters Bedrock doesn’t offer (e.g. medical-advice-specific filters).
- Latency budget is < 100ms per turn and the guardrail overhead is unacceptable.
- You want filters that run during generation (token-level filtering), not just before/after.