Azure Content Safety Endpoint
A2A v1 Azure Content Guardrails Policy
Policy Name |
A2A v1 Azure Content Guardrails Policy |
Summary |
Evaluates A2A v1 agent messages against Azure AI Content Safety for harmful content, jailbreak attempts, hallucinations, and copyrighted material |
Category |
A2A |
First Omni Gateway version available |
v1.13.0 |
Release Notes |
|
Returned Status Codes |
403 - Forbidden: Content violates Azure Content Safety policies |
503 - Service Unavailable: Azure API call failed (only when fail-open is disabled) |
Summary
The A2A v1 Azure Content Guardrails policy provides comprehensive content moderation for A2A v1.0 agent traffic by evaluating requests and responses against the Azure AI Content Safety service. The policy integrates with Azure AI Content Safety to enforce content safety policies including:
-
Content filters: Detects and blocks harmful content across four categories (Hate, SelfHarm, Sexual, and Violence) with configurable severity thresholds (
0,2,4,6). -
Prompt Shield: Detects jailbreak attempts and indirect prompt-injection attacks using Azure’s advanced detection capabilities.
-
Blocklists: Blocks content matching Azure-managed custom blocklists you define in Azure Content Safety Studio.
-
Groundedness Detection: Evaluates whether agent responses are grounded in provided reference text (hallucination detection for RAG applications).
-
Protected Material Detection: Detects known copyrighted text in agent responses.
The policy operates across three A2A v1.0 transport protocols:
-
JSON-RPC — Moderates
SendMessageandSendStreamingMessageon both request and response -
HTTP+JSON — Moderates
POST /message:sendand streaming responses -
gRPC — Pass-through without moderation in v1.0
The policy operates in independent phases:
-
Request phase: Moderates user messages before they reach the upstream agent, preventing harmful or inappropriate messages from being processed.
-
Response phase: Moderates agent responses before they reach the client, ensuring outputs comply with safety policies.
-
Streaming response phase: Best-effort moderation of streaming responses by buffering frame bodies and scanning on configurable thresholds.
When content violates safety policies, the request is rejected with a 403 error code and never reaches the agent (request phase) or the client receives a 403 instead of the agent response (response phase).
| This policy is designed for A2A v1.0 traffic only. gRPC traffic passes through without moderation in this version. |
Before You Begin
Before configuring this policy, you need:
-
Azure Account with access to Azure AI Content Safety
-
Azure Content Safety Resource created in the Azure Portal
-
Subscription Key from the Azure Portal (Keys and Endpoint section)
-
Resource Endpoint URL from the Azure Portal configured as a Flex service
Configuring Policy Parameters
Managed Omni Gateway and Omni Gateway Connected Mode
When you apply the policy from the UI, the following parameters are displayed:
Basic Configuration
| Element | Required | Description |
|---|---|---|
Yes |
Azure Content Safety endpoint base URL configured as a Flex service, for example, |
|
Azure API Key |
Yes |
Azure Content Safety subscription key. The key is passed in the |
Moderate Request |
No |
When enabled, evaluates the user message against Azure Content Safety before forwarding to the upstream agent. Rejected messages never reach the agent. Default: |
Moderate Response |
No |
When enabled, evaluates the agent response against Azure Content Safety before returning to the client. Rejected responses return |
Moderate Streaming Response |
No |
When enabled, evaluates streaming responses by buffering frame bodies and scanning on configurable thresholds. When disabled, streaming responses pass through unchanged. Default: |
Default Severity Threshold |
No |
Severity threshold applied to all four harm categories (Hate, SelfHarm, Sexual, Violence). Content with severity at or above this value is rejected. Supported values are For details, see Severity Thresholds. |
Advanced Configuration
| Element | Required | Description |
|---|---|---|
API Version |
No |
Azure Content Safety API version used for all endpoint calls. Default: To enable Groundedness Detection, override this to a supported preview version, for example, |
Enable Prompt Shield |
No |
When enabled, calls |
Hate Severity Threshold |
No |
Per-category override for the Hate harm category. Leave as |
SelfHarm Severity Threshold |
No |
Per-category override for the SelfHarm harm category. Leave as |
Sexual Severity Threshold |
No |
Per-category override for the Sexual harm category. Leave as |
Violence Severity Threshold |
No |
Per-category override for the Violence harm category. Leave as |
Blocklist Names |
No |
Names of Azure-managed blocklists (created in Azure Content Safety Studio) to evaluate against the input text. |
Enable Groundedness Detection |
No |
When enabled, calls |
Grounding Source Selector |
No |
DataWeave expression resolving the grounding source text from the canonical A2A request body. Required when Groundedness Detection is enabled. For example: |
Enable Protected Material Detection |
No |
When enabled, calls |
API Timeout (ms) |
No |
Per-request timeout for each Azure Content Safety API call in milliseconds. Must be between 1000 and 30000. Default: |
Fail Open |
No |
Determines behavior when the Azure API call fails or times out:
|
Streaming Min Buffer Chars |
No |
Minimum number of characters accumulated across consecutive SSE frame bodies before the policy calls Azure for moderation. Must be between 1 and 8192. Default: |
Max Payload Bytes |
No |
Maximum request-or-response body size (in bytes) that the policy will send to Azure. Must be between 1024 and 10000. Default: |
Sampling Rate Percent |
No |
Percentage of sessions to sample for moderation. |
Session Key Selector |
No |
DataWeave expression resolving the session identifier used by the sampler. Defaults to |
How This Policy Works
The A2A v1 Azure Content Guardrails policy integrates with Azure AI Content Safety to evaluate A2A v1.0 agent messages and responses against configurable safety policies.
Supported Methods
The policy runs only on these A2A v1.0 methods:
-
SendMessage -
SendStreamingMessage
Read-only methods (GetTask, ListTasks, push-notification methods, SubscribeToTask, GetExtendedAgentCard) and the agent-card endpoint pass through untouched. Non-A2A traffic also passes through.
Transport Support
The policy moderates these transports:
-
JSON-RPC — Full moderation on request and response
-
HTTP+JSON — Full moderation on request and response
gRPC pass-through: Requests and responses with content-type: application/grpc or application/grpc+proto skip this policy entirely and pass through unchanged. If you need gRPC moderation, route gRPC clients through an HTTP+JSON transcoder.
Request and Response Moderation
The policy supports independent evaluation for request and response:
-
Request Phase (when
moderateRequestis enabled):-
The policy extracts the raw request body.
-
The policy sends the body to Azure Content Safety APIs in parallel:
-
text:analyze— Evaluates harm categories (Hate, SelfHarm, Sexual, Violence) and checks blocklists -
text:shieldPrompt— Detects jailbreak attempts and indirect injections (whenenablePromptShieldis enabled)
-
-
If the request violates any policies, the policy blocks the request and returns a
403error code to the client. -
If the request passes, the policy forwards the original request to the upstream agent.
-
-
Response Phase — Unary (when
moderateResponseis enabled):-
The policy intercepts the agent response.
-
The policy sends the response body to Azure Content Safety APIs in parallel:
-
text:analyze— Evaluates harm categories and checks blocklists -
text:detectGroundedness— Scores the response against the grounding source (when enabled and grounding source is available) -
text:detectProtectedMaterial— Detects known copyrighted text (when enabled)
-
-
If the response violates any policies, the policy returns a
403error code to the client. -
If the response passes, the policy forwards the original response to the client.
-
-
Response Phase — Streaming (when
moderateStreamingResponseis enabled):-
The policy installs a stream handler that receives decoded SSE frames.
-
Frame bodies are accumulated in a rolling buffer.
-
When the buffer reaches
streamingMinBufferChars, it drains totext:analyze(and optionallytext:detectProtectedMaterial). -
If any rule fires, the policy replaces the current frame with a
TaskStatusUpdateEvent { state: FAILED }and closes the stream. -
On clean decisions, frames forward unchanged and the buffer resets.
-
Whole-Payload Passing
The policy sends the raw JSON body (as bytes) to Azure as the text value, not extracted text parts. This approach provides:
-
Complete coverage — Adversarial content in any field reaches Azure
-
Simplicity — No per-schema drift when A2A adds new part kinds
-
Consistency — Works uniformly across JSON-RPC and HTTP+JSON
Azure limits inputs at ~10,000 characters. Larger payloads trigger the payload_too_large rule.
|
Groundedness Detection
Groundedness detection helps detect hallucinations by evaluating whether agent responses are grounded in the provided reference text. This is particularly useful for RAG (Retrieval-Augmented Generation) applications.
To enable groundedness detection:
-
Enable groundedness detection in Advanced Configuration (
enableGroundednessDetection: true). -
Configure the Grounding Source Selector to extract the reference text from the request body.
-
Set the API Version to a preview version that supports the groundedness endpoint (for example,
2024-09-15-preview).
The grounding source selector is a DataWeave expression that extracts the reference text the agent response should be based on (typically documents or context provided in the request).
advancedConfiguration:
apiVersion: "2024-09-15-preview"
enableGroundednessDetection: true
groundingSourceSelector: "#[payload.params.message.metadata.context]"
Severity Thresholds
Azure AI Content Safety evaluates content across four harm categories and assigns a severity level to each:
-
0 — Safe (no harmful content detected)
-
2 — Low severity
-
4 — Medium severity
-
6 — High severity
The policy rejects content when the severity level is at or above the configured threshold:
| Threshold Value | Content Blocked |
|---|---|
0 |
Any flagged content (severity > 0) is blocked. This is the strictest setting. |
2 |
Content with low, medium, or high severity is blocked. This is the recommended default. |
4 |
Content with medium or high severity is blocked. This allows low-severity content. |
6 |
Only high-severity content is blocked. This is the most permissive setting. |
You can configure a default threshold that applies to all categories, and optionally override the threshold for specific categories.
Response Headers
Every moderated response includes observability headers:
| Header | Values | Description |
|---|---|---|
|
|
Final moderation decision. |
|
|
Which phase performed the moderation. Useful for understanding whether the request or response was blocked. |
|
|
Why the content was rejected or skipped. Multiple reasons are comma-separated if the content violated multiple policies. |
Headers are not emitted on gRPC pass-through traffic.
Response on Reject
When the policy blocks content, it returns a transport-appropriate error response.
JSON-RPC Transport
HTTP 403 with a JSON-RPC 2.0 error response:
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32600,
"message": "Request blocked by Azure Content Safety: severity_violence",
"data": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"domain": "a2a-protocol.org",
"reason": "FORBIDDEN",
"metadata": {
"detail": "severity_violence"
}
}
]
}
}
The error code -32600 maps to the A2A v1.0 FORBIDDEN reason code.
HTTP+JSON Transport
HTTP 403 with a Google RPC Status error response:
{
"error": {
"code": 403,
"status": "PERMISSION_DENIED",
"message": "Request blocked by Azure Content Safety: severity_violence",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"domain": "a2a-protocol.org",
"reason": "FORBIDDEN",
"metadata": {
"detail": "severity_violence"
}
}
]
}
}
Streaming Response
When a streaming response trips a rule mid-stream, the policy replaces the offending frame with a failed-status event and closes the stream:
event: status-update
data: {"jsonrpc":"2.0","id":"req-2","result":{"taskId":"task-abc","status":{"state":"FAILED","message":{"role":"agent","parts":[{"kind":"text","text":"Response blocked by Azure Content Safety: severity_hate,protected_material"}]}},"isFinal":true}}
No further frames are emitted.
Error Handling
The policy provides two error handling modes to control behavior when Azure API calls fail or timeout.
- Fail Closed (Default)
-
When Fail Open is disabled, any Azure API error or timeout results in rejection with HTTP
503and a transport-appropriate error response.-
JSON-RPC Transport:
{ "jsonrpc": "2.0", "id": null, "error": { "code": -32603, "message": "Azure Content Safety service unavailable", "data": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "domain": "a2a-protocol.org", "reason": "UNAVAILABLE", "metadata": { "detail": "service_unavailable" } } ] } }The error code
-32603maps to the A2A v1.0UNAVAILABLEreason code. -
HTTP+JSON Transport:
{ "error": { "code": 503, "status": "UNAVAILABLE", "message": "Azure Content Safety service unavailable", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "domain": "a2a-protocol.org", "reason": "UNAVAILABLE", "metadata": { "detail": "service_unavailable" } } ] } }The
x-flex-azure-guardrails-reasonheader is set toservice_unavailablefor both transports.
-
- Fail Open
-
When Fail Open is enabled, Azure API errors are logged but traffic continues without moderation. The
x-flex-azure-guardrails-reasonheader is still set toservice_unavailablefor observability, allowing you to detect partial-coverage moderation in monitoring systems.
Example Configurations
The following examples demonstrate common configuration patterns for the A2A v1 Azure Content Guardrails policy.
Minimal Configuration — Request and Response Moderation
- policyRef:
name: a2a-v1-azure-guardrails-policy-v1-0-impl
namespace: default
config:
azureEndpoint: https://llmproxy-azure-cs.cognitiveservices.azure.com
azureApiKey: "${AZURE_CONTENT_SAFETY_KEY}"
50% Sampling for Cost Control
- policyRef:
name: a2a-v1-azure-guardrails-policy-v1-0-impl
namespace: default
config:
azureEndpoint: https://llmproxy-azure-cs.cognitiveservices.azure.com
azureApiKey: "${AZURE_CONTENT_SAFETY_KEY}"
advancedConfiguration:
samplingRatePercent: 50
Half the sessions (bucketed deterministically by contextId) are moderated; the other half pass through with the sampled_out observability header.
Strict Threshold with Blocklists
This example blocks any flagged content and applies custom blocklists:
- policyRef:
name: a2a-v1-azure-guardrails-policy-v1-0-impl
namespace: default
config:
azureEndpoint: https://llmproxy-azure-cs.cognitiveservices.azure.com
azureApiKey: "${AZURE_CONTENT_SAFETY_KEY}"
moderateStreamingResponse: false
defaultSeverityThreshold: 0
advancedConfiguration:
blocklistNames:
- competitor-names
- internal-codenames
Per-Category Thresholds
This example applies different thresholds to different harm categories:
- policyRef:
name: a2a-v1-azure-guardrails-policy-v1-0-impl
namespace: default
config:
azureEndpoint: https://llmproxy-azure-cs.cognitiveservices.azure.com
azureApiKey: "${AZURE_CONTENT_SAFETY_KEY}"
defaultSeverityThreshold: 2
advancedConfiguration:
selfHarmSeverityThreshold: "4" # Allow low-severity SelfHarm discussion
violenceSeverityThreshold: "0" # Block any flagged Violence
With Groundedness Detection (Hallucination Detection)
- policyRef:
name: a2a-v1-azure-guardrails-policy-v1-0-impl
namespace: default
config:
azureEndpoint: https://llmproxy-azure-cs-eastus.cognitiveservices.azure.com
azureApiKey: "${AZURE_CONTENT_SAFETY_KEY}"
defaultSeverityThreshold: 4
advancedConfiguration:
apiVersion: "2024-09-15-preview"
enableGroundednessDetection: true
groundingSourceSelector: "#[payload.params.message.metadata.context]"
enableProtectedMaterialDetection: true
blocklistNames:
- my-blocklist
apiTimeoutMs: 10000
streamingMinBufferChars: 512
failOpen: false
samplingRatePercent: 25
sessionKeySelector: "#[payload.params.message.metadata.userId]"



