How do you authorize each Bedrock AgentCore tool call instead of trusting a broad IAM role?
An AgentCore agent authenticates once, then makes many tool calls over a session that can run up to eight hours. If those calls all ride the same broad IAM role, every call carries the same standing authority. A prompt injection that quietly redirects the agent inherits all of it. Per-call authorization breaks that by making each tool request prove itself.
The native AWS path looks like this. Front your existing MCP tools with an AgentCore Gateway, which became the single governed entry point for agent-to-tool traffic when Amazon Bedrock AgentCore reached general availability on October 13, 2025. Attach an AgentCore Policy, which is Cedar-based and, per AWS's whats-new page, generally available as of March 3, 2026, so the gateway intercepts and evaluates every agent-to-tool request at runtime against your policies before it lets the tool run. The principal and tags come from the JWT, and the action is the MCP tool call itself, so the decision happens per tool call rather than once per session. Then derive user identity from the authenticated principal, never from a client-supplied header.
Done right, that is per-call authorization at the gateway, and AWS ships most of it out of the box. The rest of this piece covers the mechanism underneath and the two spots where it still leaves you exposed.
How AgentCore inbound auth actually works
AgentCore Runtime gives you exactly one inbound auth mechanism per runtime, chosen at config time, not both at once. The runtime OAuth devguide lays out the two choices.
- IAM SigV4, the default. The caller signs the request with AWS credentials and you authorize with IAM. This is exactly where the broad-role habit sneaks in, because pointing everything at one role is the path of least resistance.
- A JWT Bearer Token via a
customJWTAuthorizer. You give it adiscoveryUrl(the OpenID Connect.well-knowndocument),allowedClients(matched against theclient_idclaim),allowedAudience(theaudclaim), andallowedScopes(thescopeclaim). AgentCore then validates the token issuer, signature, and expiry on every inbound request.
The JWT path is the one that hands you actual claims to authorize on, and it is the input AgentCore Policy reads its principal and tags from. If you want per-call decisions, the JWT authorizer is the inbound path that supports them, because SigV4 alone leaves you authorizing on AWS credentials rather than on user claims.
The on-behalf-of model, and the Runtime-User-Id trap
This is where AgentCore is genuinely strong, and also where it leaves a trap for the unwary.
When an inbound JWT arrives, AgentCore exchanges it (via bedrock-agentcore:GetWorkloadAccessTokenForJWT) for a Workload Access Token that carries both the agent workload identity and the end-user identity. That token then fetches third-party OAuth tokens (3LO, think Google Drive) from the AgentCore Token Vault, keyed by workload identity plus user id. This is AgentCore's dual inbound/outbound auth model at work, and it is the right shape: the agent acts for a specific user, not as a faceless service.
The other path is the problem. The X-Amzn-Bedrock-AgentCore-Runtime-User-Id header (reached via GetWorkloadAccessTokenForUserId) does not verify the user id against an authenticated identity. AWS documents it as an opaque identifier and tells you to lock down the IAM action bedrock-agentcore:InvokeAgentRuntimeForUser and derive the user-id from the authenticated principal, specifically to stop impersonation. If an unverified header gets to pick the user, your per-call policy ends up authorizing a claim that nobody checked. Derive identity from the JWT and leave the raw header out of the decision.
AgentCore Policy is already per-call, so what's missing?
AWS's native path is per-tool-call. AgentCore Policy first landed in preview in December 2025 and, by AWS's account, reached GA on March 3, 2026, and it evaluates each request at the gateway against Cedar policies before the tool runs, with default-deny evaluation applied per request. It is worth being precise about this, because any claim that DataShield is per-call while AgentCore is not simply gets the mechanism wrong.
Cedar does real per-call work at the gateway. It answers whether a given principal, with these tags, is allowed to invoke this tool right now, using the JWT claims and session tags at query time, and it covers admin and configuration decisions with the same engine. Lake Formation session tags and Lambda interceptors scope the same way, by IAM role and claims at the moment of the query.
What none of those three does is two specific things, and this follows from how each one works rather than from any published limitation. They evaluate a request against policy, which they genuinely do per call, but they do not put a scope ceiling on a delegated on-behalf-of token, so the token still carries whatever the authorization server granted and nothing downstream shrinks it. And they do not revoke an already-issued token before expiry, so a compromised agent keeps its access until the token times out. Those are the two gaps the rest of this piece is about, and neither one contradicts the fact that Cedar decides at the gateway on every call.
The two gaps: a scope ceiling and a next-call kill
This is the layer we built DataShield Auth to add, described as design rather than certification. We are not SOC 2 yet, and I would rather say that plainly than let you assume otherwise.
DataShield sits as a complement to AgentCore and IAM, not a replacement, and it is not a prompt proxy. In deployment terms it sits post-gateway, at the dispatch layer where a token-validated tool call is routed to the tool it targets, not inline as a proxy in front of the model and not as a sidecar inside it. It issues scope-ceiling MCP tool tokens in the RFC 9068 JWT access-token format, validates them via JWKS, and runs every tool call through a per-call dispatch pipeline in a fixed order.
The pipeline starts with the scope ceiling: the delegated token cannot exceed the ceiling, even when the upstream authorization server granted more, so on-behalf-of delegation carries a ceiling that OAuth scopes negotiated at issuance do not enforce on their own. Next it checks the call against the authority tier the caller actually holds. Then it re-checks revocation mid-session, so a revoked agent is stopped at that call rather than only when the token later expires. The call is then metered as it dispatches, and finally it is written into a sealed, hash-chained audit record.
The revocation step is the one that matters most here. When an agent starts misbehaving, waiting for a short-lived token to expire leaves it active in the meantime, whereas a mid-session re-check stops it at its next attempt.
What the MCP spec and the RFCs actually require
None of this is DataShield inventing physics. The Model Context Protocol authorization spec (revision 2025-11-25), which introduced the resource-server model back in revision 2025-06-18, classifies an MCP server as an OAuth 2.1 resource server and hands you hard requirements.
- Servers MUST validate that access tokens were issued specifically for them, using the
audaudience claim per RFC 9068. - Servers MUST publish OAuth 2.0 Protected Resource Metadata (RFC 9728) so a client can discover which authorization server issues tokens for that resource before it ever presents one.
- Clients MUST implement RFC 8707 resource indicators, binding each token to a specific server via the
resourceparameter. - Token passthrough is forbidden. You do not forward the client's token upstream.
- Authorization MUST accompany every HTTP request, even within one logical session.
- When a request needs more scope than the presented token carries, the server steps up: it returns a 403 with a
WWW-Authenticateheader so the client can negotiate the additional scope, rather than the server quietly widening the token in place. - Authorization servers SHOULD issue short-lived tokens.
The short-lived requirement is worth dwelling on. The spec's answer to a leaked or over-broad token is to make it short-lived, because it has no mechanism to ceiling a delegated token below what was granted and no way to revoke an issued token before expiry. Step-up authorization handles the opposite problem, a token that is too narrow, by letting the client ask for more, but nothing in the spec lets an intermediary hand back less scope than the authorization server granted. A short lifetime narrows the window of exposure, yet it does not shrink a token's scope or stop a token on demand. The spec's own security best practices push for fine-grained per-tool access control because each tool is its own trust boundary, which is the whole reason a broad standing role invites the confused-deputy problem. For the deeper cut on hardening the server itself, see MCP server security and the sibling piece on per-call authorization for AI agents.
Threat model: what a hijacked agent actually does
It helps to keep in-the-wild incidents and proof-of-concept research separate. As of this writing I know of no confirmed in-the-wild incident of a compromised Bedrock AgentCore agent abusing a delegated token. The named events below are researcher demonstrations, which makes them credible warnings rather than proof of active abuse.
EchoLeak (CVE-2025-32711) was disclosed by Aim Labs on June 11, 2025 as what Aim Labs called the first zero-click AI vulnerability, found in Microsoft 365 Copilot. A single crafted email, with no user interaction, used a novel "LLM Scope Violation" technique to make Copilot access and exfiltrate in-scope organizational data. It is a researcher disclosure rather than a report of an in-the-wild breach.
Aim Labs also reported CurXecute (CVE-2025-54135), a remote-code-execution chain in the Cursor IDE. By its authors' account it is a proof-of-concept for indirect prompt injection via MCP auto-start: untrusted content writes a .cursor/mcp.json file, which Cursor executes before the user accepts it, leading to RCE. It is a demonstration, not a confirmed real-world attack.
Both map onto the OWASP Top 10 for Agentic Applications, which OWASP published on December 9, 2025 and frames as its first flagship list aimed at autonomous agents. Its top category is ASI01 Agent Goal Hijack, covering attackers who hide new goals in documents, emails, and RAG results so the agent's objective is quietly rewritten. The list appears to fold classic prompt injection into ASI01, so I would read the full taxonomy (ASI02 Tool Misuse, ASI03 Identity and Privilege Abuse, on down to ASI10 Rogue Agents) rather than lean on any one-line summary of where the boundary sits. The pattern in each case is the same: broad standing authority plus untrusted input leads to exfiltration, with no traditional bug anywhere in sight.
Bedrock AgentCore authorization best practices: how to prevent tool-call overreach
These are the practices worth applying when you build authorization on AgentCore. This is an engineering threat model for the authorization control, not a full security program, so treat it as one control among several rather than a complete program.
- Use the JWT authorizer, not SigV4, as your inbound path when you want per-call decisions. Configure
allowedClients,allowedAudience, andallowedScopestightly. - Front every tool behind an AgentCore Gateway and attach an AgentCore Policy so Cedar evaluates each tool call. Do not let agents reach tools out of band.
- Derive user identity from the authenticated principal. Lock down
bedrock-agentcore:InvokeAgentRuntimeForUserand never trust theRuntime-User-Idheader as identity. If you would rather buy this, OAuth-based agent identity does the same job per token instead of per broad role. - Never pass tokens through. Exchange for a fresh, audience-scoped token per downstream call, and validate the
audclaim server-side per RFC 9068. - Bind tokens to their resource with RFC 8707 resource indicators, so a token stolen from one tool is inert at the next.
- Keep access tokens short-lived, then add what a short lifetime cannot give you: a scope ceiling on delegated tokens and a revocation path that stops an agent at its next call rather than only at expiry.
- Log every call into a tamper-evident record you can verify later, so "which call touched what, under whose authority" has a cryptographic answer.
- Assume the model is compromised and put the enforcement point outside the agent, at the gateway and the dispatch layer, where the model cannot influence it.
Govern what the agent can reach, not only what it will do
Per-call authorization governs what an agent is allowed to do. It says nothing about what the agent can reach in the first place, and that is the part most teams skip.
That second question is where tokenization earns its keep. Tokenize sensitive fields at ingest, and a hijacked agent that does slip its constraints finds tokens where the PII used to be, not raw data it can send to an attacker's domain. Pair that with per-call authorization and mid-session revocation, then seal each call into a tamper-evident audit chain you can verify after the fact. The data model behind that, what counts as sensitive and how it maps, lives in the ontology.
Prompt injection corrupts the agent's reasoning directly, so it is a weak bet to stake everything on constraining what the agent decides to do. Constrain what it can reach, and authorize each call outside the model at the granularity of the call. AWS gives you a strong per-call decision at the gateway. Add a scope ceiling, a next-call kill, and tokens in place of raw fields underneath it, and a hijacked agent has few ways left to cause damage. To watch the pipeline run against your own tools, that is what a scoped walkthrough is for.
Watch: related explainers
Two AWS sessions on AgentCore access control, plus a reality check on MCP security.
Frequently asked questions
How do you authorize each Bedrock AgentCore tool call instead of trusting a broad IAM role?
Front your MCP tools with an AgentCore Gateway and attach an AgentCore Policy (Cedar-based; AWS dates its GA to March 3, 2026), which intercepts each tool request and evaluates it against policy before the tool runs. Use the JWT inbound authorizer rather than IAM SigV4 so the decision has real claims to work with, and derive the user identity from the authenticated principal. That makes the decision per tool call rather than once per session, so a hijacked agent cannot spend one broad role across every call.
Does Amazon Bedrock AgentCore support per-tool-call authorization natively?
Yes. AgentCore Policy reached general availability in 2026 (AWS dates it to March 3) and evaluates each agent-to-tool request at the Gateway against Cedar policies before allowing or denying the call, using the principal and tags from the JWT and the MCP tool call as the action. So the native AWS path is genuinely per-tool-call. What it does not add is a scope ceiling on delegated on-behalf-of tokens or a way to revoke an issued token before it expires.
What does AgentCore Policy not do that DataShield adds?
Two things. AgentCore Policy, Lambda interceptors, and Lake Formation session tags all decide per call, scoping by IAM role and JWT claims at query time, but by the way each one works, none of them puts a scope ceiling on a delegated on-behalf-of token below what the authorization server granted, and none revokes an already-issued token before expiry. DataShield adds a scope ceiling on delegated tokens and mid-session revocation that stops a compromised agent at its next call, as a complement to AgentCore and IAM, not a replacement.
Is the AgentCore Runtime-User-Id header safe to trust for identity?
No. The X-Amzn-Bedrock-AgentCore-Runtime-User-Id header, reached via GetWorkloadAccessTokenForUserId, is documented by AWS as an opaque identifier that is not verified against an authenticated identity. AWS tells customers to restrict the IAM action bedrock-agentcore:InvokeAgentRuntimeForUser and derive the user-id from the authenticated principal to prevent impersonation. Use the JWT exchange path (GetWorkloadAccessTokenForJWT) for identity, not the raw header.
Has a Bedrock AgentCore agent been compromised in the wild?
Not that I have seen confirmed as of mid-2026. The well-known cases are researcher proofs-of-concept, not in-the-wild breaches: EchoLeak (CVE-2025-32711, disclosed June 11, 2025) in Microsoft 365 Copilot, and CurXecute (CVE-2025-54135) in the Cursor IDE, both reported by Aim Labs. They demonstrate the same failure mode AgentCore agents share: broad standing authority plus untrusted input leads to data exfiltration, which is what OWASP ASI01 Agent Goal Hijack describes.