aws-amplify-attach-service-role
UpdateApp + iam:PassRole can replace an Amplify App's iamServiceRoleArn, changing the build execution identity.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has effective amplify:UpdateApp on the target app ARN
?role trust policy allows amplify.amazonaws.com
emit
| source type | Identity |
|---|---|
| target type | BuildWorker |
| source | <principal> |
| target | <AWS::Amplify::App> |
| permissions | amplify:UpdateApp iam:PassRole |
| conditions | iam_permission role_compatibility |
| state logic | ACTIVE if both amplify:UpdateApp on the app ARN and iam:PassRole for a role trusting amplify.amazonaws.com are satisfied. CONDITIONAL(role_compatibility) if the role trust is unresolved. This edge sets up the retarget path: after CanAttachIdentity the app's next build will ExecutesAs the newly attached role, and cicd-chains cicd-modify-buildspec-executes-as fires on (CanModifyCode, new_ExecutesAs) chain. The CanAttachIdentity by itself does not grant execution; it becomes an attack step when combined with a build trigger (amplify:StartJob or auto-build) that fires after the role swap. |
Narrative
{principal.name} can replace {app.name}'s IAM service role with {role.name} (amplify:UpdateApp + iam:PassRole), changing the AWS identity the next build executes as.
Raw rule rules/derived/aws/amplify.yaml
id: aws-amplify-attach-service-role
emits: CanAttachIdentity
description: UpdateApp + iam:PassRole can replace an Amplify App's iamServiceRoleArn, changing the build
execution identity.
match:
- - principal: null
- CanPassIdentity
- role: null
where:
- ?principal has effective amplify:UpdateApp on the target app ARN
- ?role trust policy allows amplify.amazonaws.com
emit:
source_type: Identity
target_type: BuildWorker
source: <principal>
target: <AWS::Amplify::App>
permissions:
- amplify:UpdateApp
- iam:PassRole
conditions:
- iam_permission
- role_compatibility
state_logic: 'ACTIVE if both amplify:UpdateApp on the app ARN and iam:PassRole for a role trusting amplify.amazonaws.com
are satisfied. CONDITIONAL(role_compatibility) if the role trust is unresolved. This edge sets up
the retarget path: after CanAttachIdentity the app''s next build will ExecutesAs the newly attached
role, and cicd-chains cicd-modify-buildspec-executes-as fires on (CanModifyCode, new_ExecutesAs) chain.
The CanAttachIdentity by itself does not grant execution; it becomes an attack step when combined
with a build trigger (amplify:StartJob or auto-build) that fires after the role swap.'
derived_from:
- <CanPassIdentity edge_id>
false_positive_note: UpdateApp is a single API that can simultaneously change buildSpec AND iamServiceRoleArn;
the attacker can inject build commands AND swap the role in one call. The CanAttachIdentity edge models
the identity-swap half; CanModifyCode (aws-amplify-modifycode-app) models the buildSpec half. Both
may fire from a single UpdateApp call. iam:PassRole PassedToService must include amplify.amazonaws.com;
otherwise Amplify rejects the new role ARN.
narrative: '{principal.name} can replace {app.name}''s IAM service role with {role.name} (amplify:UpdateApp
+ iam:PassRole), changing the AWS identity the next build executes as.'