aws-bedrock-agent-swap-role
Swap a Bedrock Agent's execution role via UpdateAgent+PassRole to execute the orchestration loop as an attacker-chosen role.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanModifyConfiguration {'agent': None}
{'principal': None} CanPassIdentity {'role': None}
where
node_type(?agent) ==
GenericCompute
?agent.provider_type == 'AWS::Bedrock::Agent'
?role trust policy allows bedrock.amazonaws.com (or is unknown -> POTENTIAL)
iam:PassRole for ?role permits iam:PassedToService bedrock.amazonaws.com (or is unconditioned)
optional
Present → upgrade the emitted state; absent → downgrade (not a hard requirement).
{'principal': None}
CanTrigger {'agent': None}
emit
| source type | Identity |
|---|---|
| target type | Identity |
| source | ?principal |
| target | ?role |
| permissions | bedrock:UpdateAgent iam:PassRole |
| conditions | iam_permission role_compatibility |
| state logic | if ?role trust policy or iam:PassedToService is unknown/unresolved: POTENTIAL(role_compatibility); elif matched(optional[0]) or InvokeAgent path exists for ?agent: ACTIVE; else: CONDITIONAL(trigger_exists) — the role is bound but no run path is established yet; the agent must be invoked to realize the escalation. |
Narrative
{principal.name} can update Bedrock Agent {agent.name} to run as {role.name} (bedrock:UpdateAgent + iam:PassRole to bedrock.amazonaws.com); when the Agent is invoked, its orchestration loop executes with {role.name}'s credentials, giving {principal.name} effective execution as {role.name}.
Raw rule rules/derived/aws/bedrock.yaml
id: aws-bedrock-agent-swap-role
emits: CanExecuteAs
description: Swap a Bedrock Agent's execution role via UpdateAgent+PassRole to execute the orchestration
loop as an attacker-chosen role.
match:
- - principal: null
- CanModifyConfiguration
- agent: null
- - principal: null
- CanPassIdentity
- role: null
where:
- node_type(?agent) == GenericCompute
- ?agent.provider_type == 'AWS::Bedrock::Agent'
- ?role trust policy allows bedrock.amazonaws.com (or is unknown -> POTENTIAL)
- iam:PassRole for ?role permits iam:PassedToService bedrock.amazonaws.com (or is unconditioned)
optional:
- - principal: null
- CanTrigger
- agent: null
emit:
source_type: Identity
target_type: Identity
source: ?principal
target: ?role
permissions:
- bedrock:UpdateAgent
- iam:PassRole
conditions:
- iam_permission
- role_compatibility
state_logic: "if ?role trust policy or iam:PassedToService is unknown/unresolved:\n POTENTIAL(role_compatibility);\n\
elif matched(optional[0]) or InvokeAgent path exists for ?agent:\n ACTIVE;\nelse:\n CONDITIONAL(trigger_exists)\
\ \u2014 the role is bound but no run path is\n established yet; the agent must be invoked to realize\
\ the escalation."
confidence: min(contributing_confidences) * 0.95
derived_from:
- <CanModifyConfiguration edge_id for ?principal -> ?agent>
- <CanPassIdentity edge_id for ?principal -> ?role>
- <CanTrigger edge_id for ?principal -> ?agent (optional)>
false_positive_note: "Honor iam:PassedToService: a role passable only to lambda.amazonaws.com or ec2.amazonaws.com\
\ does NOT yield a Bedrock execution role \u2014 downgrade to POTENTIAL(role_compatibility) when PassedToService\
\ is absent or scoped to an incompatible service. The agent role trust policy must allow bedrock.amazonaws.com;\
\ without that, CreateAgent/UpdateAgent rejects the role. An SCP denying bedrock:UpdateAgent or iam:PassRole\
\ at the effective scope makes this BLOCKED. NOTE: This rule duplicates the provider-agnostic linchpin\
\ execute-as-via-config-identity-swap in can-execute-as.yaml. The Bedrock-specific state_logic adds\
\ nuance (trigger_exists gating for CONDITIONAL), but the base CanExecuteAs emission is handled by\
\ the linchpin. Deduplication is automatic on (type=CanExecuteAs, source, target, scope)."
narrative: '{principal.name} can update Bedrock Agent {agent.name} to run as {role.name} (bedrock:UpdateAgent
+ iam:PassRole to bedrock.amazonaws.com); when the Agent is invoked, its orchestration loop executes
with {role.name}''s credentials, giving {principal.name} effective execution as {role.name}.'