aws-imagebuilder-s3-component-uri-can-modify-code
Overwrite a component's S3-backed document (s3:PutObject on the component URI bucket/key) to inject malicious steps that execute on the next build as the build instance role.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'component': None}
ContainsResourceReference {'s3_object': None}
{'principal': None} CanWrite {'s3_object': None}
{'recipe': None} ContainsResourceReference {'component': None}
{'pipeline': None} ContainsResourceReference {'recipe': None}
where
node_type(?component) ==
BuildWorker
?component.provider_type == 'AWS::ImageBuilder::Component'
?component.uri != null # component uses S3-backed document, not inline data
node_type(?s3_object) == ObjectStorage
node_type(?recipe) == BuildWorker
?recipe.provider_type in ['AWS::ImageBuilder::ImageRecipe', 'AWS::ImageBuilder::ContainerRecipe']
node_type(?pipeline) == BuildWorker
?pipeline.provider_type == 'AWS::ImageBuilder::ImagePipeline'
emit
| source type | Identity |
|---|---|
| target type | BuildWorker |
| source | ?principal |
| target | ?pipeline |
| permissions | s3:PutObject |
| conditions | iam_permission resource_policy |
| state logic | ACTIVE when the principal has effective s3:PutObject on the exact S3 bucket/key referenced in the component's uri field, and the component is referenced by an active pipeline (the modification will be executed on the next build). CONDITIONAL(resource_policy) when S3 write is granted only via a bucket policy that may not remain in place. POTENTIAL when the component is present but it is unclear whether any active pipeline references it (pipeline reference unresolved). BLOCKED when an SCP or permission boundary denies s3:PutObject on the bucket. |
Narrative
{principal.name} can overwrite the S3 object at {s3_object.name} (s3:PutObject) that backs the Image Builder component document for {component.name}. On the next build of {pipeline.name}, the SSM agent will download and execute the attacker-modified document as the build instance role {role.name}, without any imagebuilder:* API call by the attacker.
Raw rule rules/derived/aws/imagebuilder.yaml
id: aws-imagebuilder-s3-component-uri-can-modify-code
emits: CanModifyCode
description: Overwrite a component's S3-backed document (s3:PutObject on the component URI bucket/key)
to inject malicious steps that execute on the next build as the build instance role.
match:
- - component: null
- ContainsResourceReference
- s3_object: null
- - principal: null
- CanWrite
- s3_object: null
- - recipe: null
- ContainsResourceReference
- component: null
- - pipeline: null
- ContainsResourceReference
- recipe: null
where:
- node_type(?component) == BuildWorker
- ?component.provider_type == 'AWS::ImageBuilder::Component'
- '?component.uri != null # component uses S3-backed document, not inline data'
- node_type(?s3_object) == ObjectStorage
- node_type(?recipe) == BuildWorker
- ?recipe.provider_type in ['AWS::ImageBuilder::ImageRecipe', 'AWS::ImageBuilder::ContainerRecipe']
- node_type(?pipeline) == BuildWorker
- ?pipeline.provider_type == 'AWS::ImageBuilder::ImagePipeline'
emit:
source_type: Identity
target_type: BuildWorker
source: ?principal
target: ?pipeline
permissions:
- s3:PutObject
conditions:
- iam_permission
- resource_policy
state_logic: ACTIVE when the principal has effective s3:PutObject on the exact S3 bucket/key referenced
in the component's uri field, and the component is referenced by an active pipeline (the modification
will be executed on the next build). CONDITIONAL(resource_policy) when S3 write is granted only via
a bucket policy that may not remain in place. POTENTIAL when the component is present but it is unclear
whether any active pipeline references it (pipeline reference unresolved). BLOCKED when an SCP or
permission boundary denies s3:PutObject on the bucket.
confidence: min(contributing_confidences) * 0.87
derived_from:
- ?component ContainsResourceReference ?s3_object (component.uri -> S3 bucket/key)
- ?principal CanWrite ?s3_object (s3:PutObject effective permission)
false_positive_note: "Only applies when the component uses the `uri` field \u2014 an inline `data` component\
\ cannot be overwritten via S3 (the document is stored in Image Builder's backing store, not in the\
\ caller-accessible S3 path). Verify the S3 bucket and key match exactly the component's `uri` value;\
\ a s3:PutObject on an unrelated bucket is not this path. The component must be active in a referenced\
\ recipe in a running pipeline; a deprecated or orphaned component is POTENTIAL. Do not conflate S3-backed\
\ component access with imagebuilder:CreateComponent access \u2014 these are independent paths."
narrative: '{principal.name} can overwrite the S3 object at {s3_object.name} (s3:PutObject) that backs
the Image Builder component document for {component.name}. On the next build of {pipeline.name}, the
SSM agent will download and execute the attacker-modified document as the build instance role {role.name},
without any imagebuilder:* API call by the attacker.'