Skip to main content
This article shows you how to attach guardrails to a hosted agent in Microsoft Foundry. Define guardrails in a Responsible AI (RAI) policy that you reference from the agent definition. The platform applies these guardrails at runtime. This article covers two kinds of guardrails:
  • Content safety controls screen the prompts your agent receives and the responses it returns, so harmful content is filtered according to your organization’s safety configuration.
  • Network egress controls (preview) govern the outbound connections your agent makes, so it reaches only the destinations you allow.
You reference the guardrail by its RAI policy resource ID on the agent definition. You can attach it when you deploy by using the Azure Developer CLI (azd), the Python SDK, or the REST API. The same attach steps apply to both kinds of guardrails. To learn what guardrails are, the risks they detect, and how to create one, see Guardrails and controls overview. If your agent uses the invocations protocol, attaching a policy isn’t enough on its own. You also declare where the text to screen lives in your request and response bodies. See Add a guardrail to an agent that uses the invocations protocol.

Prerequisites

  • A Microsoft Foundry project.
  • A hosted agent, or a container image ready to deploy as one. See Deploy a hosted agent.
  • A guardrail (RAI policy) on the Foundry resource, and its full Azure Resource Manager (ARM) resource ID. To create one in the Foundry portal, see Configure guardrails and controls. For a network egress guardrail, you can also create the policy with azd provision. The ARM resource ID has this form:
  • For the Azure Developer CLI method: the azd ai agent extension, version 1.0.0-beta.12 or later.
  • For the Python SDK method: the Azure AI Projects client library for Python, version 2.2.0 or later:
    To configure moderation for the invocations protocol, use version 2.7.0 or later:

How guardrails apply to hosted agents

A hosted agent definition has an optional rai_config setting with a rai_policy_name field. Set rai_policy_name to the full ARM resource ID of your guardrail’s RAI policy. The platform applies that policy to the agent’s prompts and responses. When you omit rai_config, the agent runs without a content safety guardrail. When you include rai_config but omit rai_policy_name, the platform applies the default policy, Microsoft.DefaultV2. Provide a custom policy when you need stricter or organization-specific filtering. Always use the full ARM resource ID for rai_policy_name, not the bare policy name.
Don’t rely on deploy-time validation to catch a bad policy ID. On many subscriptions an agent that references a policy that doesn’t exist is created successfully and reports active, but no content filtering is applied - the guardrail fails open and harmful prompts reach the agent. Confirm the policy exists on the account, then test the guardrail before you rely on the agent’s content safety.
rai_config is the shape the Foundry API accepts, so the Python SDK and REST examples in this article set it directly. The Azure Developer CLI doesn’t expose rai_config in azure.yaml; it uses a policies list instead and maps it to rai_config when it deploys.

Protocol differences

How much configuration a guardrail needs depends on the protocol your agent exposes:
On the invocations protocol, a policy attached without invocations_moderation is inert. The platform has no way to find the text in your custom body shapes, so it doesn’t screen anything and requests pass through unfiltered. The agent still deploys and returns HTTP 200, which makes the gap easy to miss.

Add a guardrail

Choose the method you use to deploy the agent. These examples attach a guardrail to an agent on the responses protocol. On the invocations protocol, you also need moderation settings, which Add a guardrail to an agent that uses the invocations protocol covers.
When you use azd, declare the guardrail in the policies list on the azure.ai.agent service in azure.yaml. Add an entry with type: rai_policy and set raiPolicyName to the full ARM resource ID of the RAI policy. When you deploy, azd maps that entry to rai_config.rai_policy_name on the agent definition it sends to Foundry.
  1. In your azure.yaml, add a policies list to the agent service:
  2. Deploy the agent:
The platform attaches the guardrail when it creates the agent version.
In azure.yaml the field is camelCased as raiPolicyName. The deprecated standalone agent.yaml uses the snake_case rai_policy_name. Both map to rai_config.rai_policy_name on the agent version. Don’t declare the guardrail in agent.manifest.yaml - azd reads that file only during azd ai agent init and ignores it at deploy time.

Verify the guardrail is applied

Get the agent version and confirm that rai_config.rai_policy_name holds your policy ID.
The response includes the policy you set:

Test content safety filtering

To confirm that the guardrail filters content, send a prompt that violates your safety policy to the agent’s Responses endpoint. The platform screens the prompt at the input stage and rejects it before the agent runs.
A blocked prompt returns HTTP 400 with a content_filter error:
A prompt that passes the policy returns HTTP 200 with the agent’s response. If a harmful prompt isn’t blocked, check in this order:
  1. The policy named by rai_policy_name actually exists on the account. A nonexistent policy fails open with no error. List the policies on the account and confirm the final segment of rai_policy_name matches one of them:
  2. The policy is configured to filter the relevant content category and severity.
The guardrail applies to streaming requests too. By using "stream": true, a violating prompt is rejected with the same HTTP 400 before any event is emitted.

Add a guardrail to an agent that uses the invocations protocol

On the responses protocol, the platform knows the request and response shapes, so rai_policy_name is all you need. The invocations protocol accepts request and response bodies that your agent defines, so the platform can’t tell which fields hold user or agent text. Add an invocations_moderation object to rai_config that declares where the text lives. Until you do, the policy is attached but screens nothing.

Moderation settings

Set input_content_type or output_content_type to text when that body is plain text. The platform then screens the body itself and you don’t provide paths for that direction. You can attach only one RAI policy to an agent, so invocations_moderation applies to that single policy.

Path expressions

input_paths and output_paths accept $ for the document root, dot notation for members, array indexes, and [*] wildcards. For example, $.messages[*].content selects the content field of every element in the messages array. When a path selects several values, the platform joins them and screens them together.

Stream selectors

For a streamed response, the platform reads the type field of each event and compares it to event_type. On a match, it reads the field named by text_field and screens that text. Both event_type and text_field are exact, case-sensitive matches against top-level properties of the event’s JSON payload. You can’t select a nested field. text_field is a field name, not a path expression. Use content, not $.content. An event whose type matches no selector, or whose text_field names no property, contributes no text. That event’s content goes unscreened, and if no selector ever yields text, the response isn’t screened at all. When you omit text_field, the platform uses delta.

Response modes

response_mode declares the shapes your agent can return. It applies only to output: input screening runs regardless of the value you set. For output, the platform inspects the response Content-Type and runs one check, using the streaming check for text/event-stream and the buffered check otherwise. Declare every shape your agent can return. A successful response that carries content in a shape you didn’t declare is rejected with HTTP 502 rather than skipping moderation. Use both only when your agent genuinely answers both ways. Output screening applies to successful responses that carry content. The platform doesn’t screen error responses from your container or empty acknowledgments.

Limits

Content safety screening has bounds that affect large payloads: The platform also forwards a request unscreened when it can’t parse the body as JSON or when input_paths selects nothing. Confirm your paths match your real request bodies rather than assuming a deployed policy is screening them.

Add the moderation settings

Choose the method you use to deploy the agent.
Add an invocationsModeration block to the rai_policy entry in azure.yaml. These settings use camel case, and azd maps them to the snake case names that the API accepts.
  1. In your azure.yaml, add invocationsModeration to the rai_policy entry. This example screens the message field of the request. The agent streams events shaped like {"type": "token", "content": "..."} and a final {"type": "done", "full_text": "..."}.
  2. Deploy the agent:
    The platform applies the moderation settings when it creates the agent version.
azd checks the block before it deploys, so a structural mistake fails locally instead of at runtime. For example, declaring moderation on an agent that doesn’t expose the invocations protocol returns:
These checks cover structure, not meaning. azd can’t tell whether your paths and field names match the bodies your agent actually sends, so verify that yourself with the test in Test the moderation settings.

What a blocked invocation looks like

The response to a blocked request depends on which stage the platform blocks and whether your agent streams. A blocked request returns HTTP 400 before your agent runs. The message ends with the request ID, which you can use when you file a support request:
A blocked buffered response also returns HTTP 400, with a message that names the output stage. A blocked streamed response is different. The platform sends response headers before it screens the agent’s output, so the status stays HTTP 200. The platform discards the events it was holding, sends a single error event, and ends the stream:
Handle this event in your client. Treat it as terminal. Earlier events might already have reached the client, so the user could see partial output before the block. A 200 status alone doesn’t mean the response passed the policy.

Test the moderation settings

To confirm your settings screen the right fields, send a request that your policy is configured to block and check that the platform blocks it. If you deployed with azd, put the request body in a file, such as blocked-request.json:
Then invoke the agent with that file:
azd reads the protocol from azure.yaml. Send the body as a file rather than as a message argument: azd sends a message argument as text/plain, and an inputContentType of json can’t parse it, so the platform forwards the request unscreened. You can also call the endpoint directly:
If the request isn’t blocked, check that:
  • input_paths matches the field that holds the user text. A path that selects nothing means nothing is screened.
  • Each text_field is a field name, such as content, rather than a path such as $.content.
  • Each event_type matches the type value your agent sends in its streamed events.
  • Your event_type and text_field values match your agent’s casing exactly, and name top-level properties rather than nested ones.
  • The policy filters the relevant content category and severity.
If requests fail with HTTP 502 instead, response_mode probably doesn’t match what your agent returns. Set it to both if your agent answers both ways.

Network egress controls (preview)

Network egress controls are in preview. They apply to hosted agents only and don’t affect prompt-based agents or model deployments. Configure them by using the 2026-05-15-preview API version of the RAI policy. Preview features are provided without a service-level agreement and are not intended to be used in production or in a live operating environment. This feature consists of tooling only. Customers are responsible for understanding the data handling practices of any endpoints receiving data.
Content safety controls screen prompts and responses. Network egress controls govern the outbound connections your hosted agent makes. You define ordered rules that allow, deny, transform, or rewrite outbound requests by destination host, and the platform enforces them inside the agent’s sandbox before traffic leaves the runtime. Egress rules are stored in the same RAI policy you attach in the previous sections, so the azd, Python SDK, and REST API attach steps apply them automatically.

How egress rules are evaluated

  • The system evaluates rules in order, from top to bottom. The first matching rule wins.
  • If no rule matches, the policy’s default action applies. Set the default action to Deny for an allow list (recommended) or Allow for a deny list.
  • When you apply an egress policy, the agent runtime automatically allow lists foundational domains it needs to function. A Deny default action doesn’t block this required platform connectivity, so you don’t need to add rules for it.
  • Each rule matches on the request host. Wildcards such as *.contoso.com are supported.
  • Rule actions are Allow, Deny, Transform (allow the request and modify its headers), and Rewrite (redirect the request to another destination).
  • Evaluation is fail-closed: if the policy can’t be evaluated, the request is denied.

Rule limits

You can add a maximum of 480 egress rules per policy. This limit applies to all egress rule actions: Allow, Deny, Transform, and Rewrite. To request an increase to this limit, create an Azure support request.

Choose an enforcement mode

Deploy in Audit mode first, review the egress decisions, refine your rules, and then switch to Enforce.
Audit mode changes only how Deny actions behave: a request that would be denied is logged instead of blocked. Transform and Rewrite actions are applied in both Audit and Enforce modes, so header transforms and redirects still take effect while you audit.

Common egress control use cases

Use egress controls to limit a hosted agent to the external services required for its task. The following patterns are common starting points: Package managers and SDKs can follow redirects or use separate download hosts. Don’t assume that the registry host is the only destination required. Use Audit mode with representative workloads to identify the complete host set.

Add egress rules by using the Azure Developer CLI

Add the RAI policy ARM resource to your azd project’s Bicep infrastructure. The azd provision command deploys the resource through ARM.
  1. Add the following Bicep to the resource-group-scoped infrastructure for the resource group that contains your Foundry resource:
    Reference: Microsoft.CognitiveServices accounts/raiPolicies.
  2. Provision the policy:
The command creates or updates the Microsoft.CognitiveServices/accounts/raiPolicies child resource. Use the RAI_POLICY_ID output as the full policy resource ID when you attach the guardrail to a hosted agent.

Add egress rules by using the REST API

An RAI policy stores egress rules in the egressPolicy property. Create or update the policy by using the Azure Resource Manager RAI Policies - Create Or Update operation with the 2026-05-15-preview API version:
  • Set egressPolicy.mode to Enforced to block traffic, or Audit to log would-deny events without blocking.
  • Set egressPolicy.defaultAction to Deny for an allow list or Allow for a deny list.
  • Set each rule’s action.actionType to Allow, Deny, Transform, or Rewrite.
To review the configured rules, send a GET request to the same URL and inspect properties.egressPolicy. For a complete request body that combines a default action with several rule types, see the PutRaiPolicyWithEgress.json example in the Azure REST API specs.

Example: restrict a dependency research agent

Consider a coding agent that researches Python dependencies and their source repositories. It needs to read package metadata from PyPI, download package files, and retrieve repository metadata from the GitHub API. It shouldn’t connect to unrelated internet destinations. Start with the following egress policy in Audit mode. Replace the egressPolicy object in the REST request from the previous section with this object:
Validate and enforce the policy:
  1. Create or update the RAI policy with mode set to Audit.
  2. Attach the policy to the hosted agent and deploy a new agent version.
  3. Run representative tasks, such as retrieving Python package metadata, inspecting a package’s source repository, and downloading a package.
  4. Have the agent attempt a request to an unrelated host, such as example.com. Audit mode allows the request but records that the policy would deny it.
  5. Review the egress decisions. Add any legitimate redirect or download hosts that appear in the agent’s normal workflow.
  6. Change mode from Audit to Enforced, update the RAI policy, and deploy a new agent version.
  7. Start a new session or resume the session, and run the same tasks again. Running sandboxes don’t reload policy changes. Requests to the approved package and source-control hosts succeed. A request to an unapproved host returns HTTP 403.
The exact host set depends on the package manager, SDK, and services that your agent uses. Keep the allow list specific to the workload instead of copying the example unchanged. For a runnable hosted-agent sample that exercises Allow, Deny, Transform, Rewrite, Audit, wildcard, and rule-ordering scenarios, see the egress control sample.

Transform request headers

When a rule’s action.actionType is Transform (or Rewrite), you can modify the headers of the outbound request by using an action.headers array. Each entry describes one header operation:
Each header object supports the following fields: You must include headers when actionType is Transform. You can omit headers when actionType is Rewrite. Header transforms apply only to requests that match the rule.
Header transforms support static values and managed identity value references. For a managed identity value reference, set valueRef.managedIdentityRef.resource to the target resource URI, such as https://storage.azure.com/. Set format to the bearer scheme with the {token} placeholder. Grant the deployed agent’s instance_identity.principal_id the required role on the target resource. Secret value references aren’t supported during preview.

Header operations

The three operations differ only in how they treat a header that’s already present on the outbound request: Use Set to force a header to a specific value regardless of what the agent sent. Use Insert to supply a default only when the agent didn’t already set the header. Use Remove to strip a header before the request leaves the runtime.

Add egress rules in the portal

You can also author egress rules in the Foundry portal as a Network control on a guardrail:
  1. In the Foundry portal, create or edit a guardrail, and then expand the Network control.
Screenshot of the Network control in a guardrail showing the Egress rules row and the Outbound requests default action.
  1. Select Egress rules, and set the Outbound requests default action to Deny or Allow.
  2. Select Add rules, choose a Mode (Audit or Enforce), enter a Host match and an Action, and then select Add. Reorder rules as needed; the first match wins. For a Transform action, use a Static value or Managed identity value source for the header. The Secret reference value source appears in the dialog but isn’t supported during preview. Don’t use this option. For more information, see Preview limitations.
Screenshot of the Create egress rules dialog with Audit and Enforce modes, a host match field, and an action list.
  1. Select Create, and then assign the guardrail to your hosted agent.
For details about creating and assigning guardrails in the portal, see Configure guardrails and controls.

Certificate handling

To inspect HTTPS traffic, the hosted-agent runtime injects the egress proxy’s certificate authority (CA) into the sandbox trust bundle. The proxy CA is infrastructure-specific: it can differ across hosted-agent clusters and regions, and it rotates over time (currently about every 30 days). Treat the CA bundle as runtime configuration. Don’t pin, copy, or persist it. Configure TLS clients to read the runtime-provided CA bundle from the standard environment variables that are already present in the sandbox: For example, with Python requests:
Keep these constraints in mind:
  • Don’t pin the CA subject, public key, thumbprint, or file contents. Any of these values can change on rotation or differ by cluster.
  • Don’t persist the injected CA to a container image, persistent volume, snapshot, or source control. The CA is runtime infrastructure, not application configuration.
  • Rotation can happen while a sandbox is running. Long-running processes might need to reload their TLS configuration or restart.
  • If you must build a single custom bundle (for example, to combine enterprise roots with the runtime roots), build it at process startup from the current runtime bundle and treat it as temporary:

View egress decisions

The agent sends network egress decisions to your project’s Application Insights and trace monitoring tools. You can view these decisions in the Foundry portal playground and in Application Insights to confirm that network egress behavior aligns with your configured policy.

In the Foundry portal playground

To view egress decisions in the trace timeline:
  1. Sign in to Microsoft Foundry and open your project’s playground.
  2. Run or select an agent invocation to open its trace.
  3. Select the Trajectories tab to see the full trace timeline.
  4. Expand the trace nodes until you see a span named Network egress decision. It appears next to the request that triggered it.
  5. Select the span to review the decision details.
Screenshot of the Trajectories tab in the Foundry portal playground, showing a Network egress decision span in the trace timeline.
The span details show the information you need to understand why a request was allowed or denied: Allowed requests appear with a success status, and denied requests appear with a failure status, so you can spot blocked calls without leaving the trace view.

In Application Insights

To review egress decisions in Application Insights logs:
  1. Locate your project’s Application Insights resource:
    1. Go to the Foundry portal.
    2. Select the Operate tab.
    3. Select Admin.
    4. Search for and select your project.
    5. Open the Connected resources tab.
    6. Find the AppInsights connected resource and copy its Target URI.
    Each project should have a single Application Insights connection. If Application Insights isn’t configured, select Add connection and add an Application Insights resource for the project.
  2. Open the Application Insights resource in the Azure portal and go to Logs. Run the following query to view recent network egress decisions:
Each event includes details such as the destination host, matched rule, decision, and enforcement mode.

What a blocked request looks like

When a rule denies an outbound call, the egress proxy returns an HTTP 403 response to the agent’s network client. The agent handles the error with its own logic. For example, if the blocked call was a tool call, the agent typically reports that the tool call failed and tries a different approach. Policy internals aren’t exposed to end users.

Preview limitations and what’s coming next

Network egress controls are an additive feature. During preview:
  • Egress controls apply to hosted agents only.
  • Enforcement happens inside the Foundry-managed agent sandbox. Egress controls complement your own network controls, such as Azure Firewall, rather than replace them. They don’t delegate enforcement to a customer-managed firewall, and they aren’t centrally enforced through Azure Policy.
  • In the portal, rules match on host.
The following capabilities aren’t available yet and are planned for future updates:
  • Secret header values — Injecting a header value from a secret reference isn’t supported during preview.
  • Rule types such as Azure service tags and IP address ranges.
  • MCP tool policies, PII and data-loss-prevention inspection, and custom webhook hooks.