aws-bedrock-action-group-lambda-redirect
Redirect a Bedrock Agent action group's backing Lambda to an attacker-controlled Lambda, injecting code into the agent's execution path.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?agent) ==
GenericCompute
?agent.provider_type == 'AWS::Bedrock::Agent'
?principal has EFFECTIVE bedrock:UpdateAgentActionGroup on ?agent
?principal has EFFECTIVE bedrock:PrepareAgent on ?agent
emit
| source type | Identity |
|---|---|
| target type | Compute |
| source | ?principal |
| target | ?agent |
| permissions | bedrock:UpdateAgentActionGroup bedrock:PrepareAgent |
| conditions | iam_permission |
| state logic | ACTIVE when the principal holds both bedrock:UpdateAgentActionGroup and bedrock:PrepareAgent on the Agent (the change requires PrepareAgent to take effect); CONDITIONAL(iam_permission) if PrepareAgent is missing or scope is ambiguous. An SCP or explicit deny on either action makes this BLOCKED. Note: an existing InvokeAgent trigger means the redirected Lambda fires on the next agent turn without further attacker action (run path established). |
Narrative
{principal.name} can redirect Bedrock Agent {agent.name}'s action group to point at an attacker-controlled Lambda (bedrock:UpdateAgentActionGroup + bedrock:PrepareAgent); when the Agent runs, it invokes that Lambda, executing attacker code in the action-group Lambda's execution role. See lambda rules for the full CanExecuteAs derivation.
Raw rule rules/derived/aws/bedrock.yaml
id: aws-bedrock-action-group-lambda-redirect
emits: CanModifyCode
description: Redirect a Bedrock Agent action group's backing Lambda to an attacker-controlled Lambda,
injecting code into the agent's execution path.
match:
- - principal: null
- CanModifyConfiguration
- agent: null
where:
- node_type(?agent) == GenericCompute
- ?agent.provider_type == 'AWS::Bedrock::Agent'
- ?principal has EFFECTIVE bedrock:UpdateAgentActionGroup on ?agent
- ?principal has EFFECTIVE bedrock:PrepareAgent on ?agent
emit:
source_type: Identity
target_type: Compute
source: ?principal
target: ?agent
permissions:
- bedrock:UpdateAgentActionGroup
- bedrock:PrepareAgent
conditions:
- iam_permission
state_logic: 'ACTIVE when the principal holds both bedrock:UpdateAgentActionGroup and bedrock:PrepareAgent
on the Agent (the change requires PrepareAgent to take effect); CONDITIONAL(iam_permission) if PrepareAgent
is missing or scope is ambiguous. An SCP or explicit deny on either action makes this BLOCKED. Note:
an existing InvokeAgent trigger means the redirected Lambda fires on the next agent turn without further
attacker action (run path established).'
confidence: min(contributing_confidences) * 0.9
derived_from:
- <CanModifyConfiguration edge_id for ?principal -> ?agent>
false_positive_note: "Changing only the action group's OpenAPI schema (not the Lambda ARN field) does\
\ NOT yield code control \u2014 do not emit this edge for schema-only changes. Verify that the principal's\
\ effective permissions cover the Lambda ARN field in UpdateAgentActionGroup (the API updates the\
\ whole action group object, so IAM-level this is all-or-nothing, but check SCP/boundary restricting\
\ the call). PrepareAgent is required to deploy the draft; without it the change sits in DRAFT state\
\ and the agent continues running the old action group. Escalation to the Lambda execution role: cite\
\ aws-lambda-execute-as-via-code (lambda rules) which fires on CanModifyCode(?principal, ?lambda)\
\ + ExecutesAs(?lambda, ?lambdaRole); do not re-derive CanExecuteAs here."
narrative: '{principal.name} can redirect Bedrock Agent {agent.name}''s action group to point at an
attacker-controlled Lambda (bedrock:UpdateAgentActionGroup + bedrock:PrepareAgent); when the Agent
runs, it invokes that Lambda, executing attacker code in the action-group Lambda''s execution role.
See lambda rules for the full CanExecuteAs derivation.'