aws-sc-s3-template-write-modifies-code

Write access to the S3 object backing a Service Catalog product version's template (LoadTemplateFromURL): the next ProvisionProduct or UpdateProvisionedProduct loads the attacker's template and executes it as the launch role. cicd-chains propagates this CanModifyCode + ExecutesAs into CanExecuteAs.

derived aws emits CanModifyCode

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanWrite {'template_object': None} {'product': None} ContainsResourceReference {'template_object': None}

where

node_type(?template_object) == ObjectStorage # S3 bucket/key from LoadTemplateFromURL node_type(?product) == BuildWorker # AWS::ServiceCatalog::CloudFormationProduct ?product version Info.LoadTemplateFromURL references ?template_object.s3_uri (no version-ID pin) ?product has a LaunchRole constraint (RoleArn non-empty)

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

{'principal': None} CanTrigger {'product': None}

emit

source typeIdentity
target typeCompute
source?principal
target?product
permissionss3:PutObject
conditionsrun_path iam_permission
state logicCONDITIONAL(run_path) by default — overwriting the S3 template object does NOT immediately execute; a ProvisionProduct or UpdateProvisionedProduct call must load the updated URL. ACTIVE when matched(optional[0]): the principal can ALSO trigger provisioning (servicecatalog:ProvisionProduct / UpdateProvisionedProduct), closing the run path. POTENTIAL(run_path) when the product version URL pins a specific S3 object version ID (i.e., the URL includes ?versionId=...) — overwriting the latest object does not change what Service Catalog loads; do not emit CONDITIONAL in that case. Inherit weakest with the CanWrite edge on ?template_object (an S3 bucket policy or SCP blocking s3:PutObject makes this BLOCKED).

Narrative

{principal.name} can overwrite the S3 template object {template_object.name} referenced by product {product.name}'s version (s3:PutObject on {template_object.name}). The next ProvisionProduct or UpdateProvisionedProduct call against that version loads the attacker's template, which executes as the launch role bound to {product.name}.

Raw rule rules/derived/aws/servicecatalog.yaml

id: aws-sc-s3-template-write-modifies-code
emits: CanModifyCode
description: 'Write access to the S3 object backing a Service Catalog product version''s template (LoadTemplateFromURL):
  the next ProvisionProduct or UpdateProvisionedProduct loads the attacker''s template and executes it
  as the launch role. cicd-chains propagates this CanModifyCode + ExecutesAs into CanExecuteAs.'
match:
- - principal: null
  - CanWrite
  - template_object: null
- - product: null
  - ContainsResourceReference
  - template_object: null
where:
- 'node_type(?template_object) == ObjectStorage  # S3 bucket/key from LoadTemplateFromURL'
- 'node_type(?product) == BuildWorker            # AWS::ServiceCatalog::CloudFormationProduct'
- ?product version Info.LoadTemplateFromURL references ?template_object.s3_uri (no version-ID pin)
- ?product has a LaunchRole constraint (RoleArn non-empty)
optional:
- - principal: null
  - CanTrigger
  - product: null
emit:
  source_type: Identity
  target_type: Compute
  source: ?principal
  target: ?product
  permissions:
  - s3:PutObject
  conditions:
  - run_path
  - iam_permission
  state_logic: "CONDITIONAL(run_path) by default \u2014 overwriting the S3 template object does NOT immediately\
    \ execute; a ProvisionProduct or UpdateProvisionedProduct call must load the updated URL. ACTIVE when\
    \ matched(optional[0]): the principal can ALSO trigger provisioning (servicecatalog:ProvisionProduct\
    \ / UpdateProvisionedProduct), closing the run path. POTENTIAL(run_path) when the product version\
    \ URL pins a specific S3 object version ID (i.e., the URL includes ?versionId=...) \u2014 overwriting\
    \ the latest object does not change what Service Catalog loads; do not emit CONDITIONAL in that case.\
    \ Inherit weakest with the CanWrite edge on ?template_object (an S3 bucket policy or SCP blocking\
    \ s3:PutObject makes this BLOCKED)."
  confidence: 0.85
  derived_from:
  - ?principal CanWrite ?template_object
  - ?product ContainsResourceReference ?template_object (LoadTemplateFromURL)
  - ?product LaunchRole constraint present
  - cicd-chains.yaml cicd-modify-buildspec-executes-as (consumes this CanModifyCode + ExecutesAs)
  false_positive_note: "The S3 write alone is NOT an immediate code-injection; a provisioning trigger\
    \ must follow. A product version URL that includes a specific S3 version ID (versionId query param)\
    \ is NOT affected by overwriting the latest object version \u2014 downgrade to POTENTIAL(run_path)\
    \ or omit. Verify the LoadTemplateFromURL value from DescribeProvisioningArtifact.Info does NOT contain\
    \ a versionId pin. Only emit when the product has a LaunchRole constraint. cicd-chains collapses this\
    \ CanModifyCode + ExecutesAs into CanExecuteAs \u2014 do not re-derive CanExecuteAs here."
  narrative: '{principal.name} can overwrite the S3 template object {template_object.name} referenced
    by product {product.name}''s version (s3:PutObject on {template_object.name}). The next ProvisionProduct
    or UpdateProvisionedProduct call against that version loads the attacker''s template, which executes
    as the launch role bound to {product.name}.'
move · open · esc close