aws-sc-create-artifact-modifies-code

servicecatalog:CreateProvisioningArtifact adds a new product version carrying an attacker-controlled CFN template. The next ProvisionProduct or UpdateProvisionedProduct using that version executes the attacker's template as the launch role bound to the product. 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} CanModifyCode {'product': None}

where

node_type(?product) == BuildWorker # AWS::ServiceCatalog::CloudFormationProduct ?principal has EFFECTIVE servicecatalog:CreateProvisioningArtifact on ?product ?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
permissionsservicecatalog:CreateProvisioningArtifact servicecatalog:UpdateProvisioningArtifact?
conditionsiam_permission version_active run_path
state logicACTIVE when ?principal has EFFECTIVE servicecatalog:CreateProvisioningArtifact on ?product AND matched(optional[0]): the principal can ALSO trigger provisioning (ProvisionProduct / UpdateProvisionedProduct), closing the run path, AND the new version becomes the active/default version (set as default via servicecatalog:UpdateProvisioningArtifact or Active=true at creation). CONDITIONAL(run_path) when the principal cannot directly trigger provisioning — another principal must call ProvisionProduct to realize the escalation. CONDITIONAL(version_active) when the new version is not yet set as the default (requires a subsequent UpdateProvisioningArtifact to activate it or an explicit version ID at ProvisionProduct time). UpdateProvisioningArtifact is required for ACTIVE state. BLOCKED when an SCP or permission boundary denies servicecatalog:CreateProvisioningArtifact at the effective scope, or when the product has no LaunchRole constraint.

Narrative

{principal.name} can add a new product version to {product.name} (servicecatalog:CreateProvisioningArtifact), supplying an attacker-controlled CloudFormation template. When that version is used for a future ProvisionProduct or UpdateProvisionedProduct, the template executes as the launch role bound to {product.name}. cicd-chains propagates this to CanExecuteAs.

Raw rule rules/derived/aws/servicecatalog.yaml

id: aws-sc-create-artifact-modifies-code
emits: CanModifyCode
description: servicecatalog:CreateProvisioningArtifact adds a new product version carrying an attacker-controlled
  CFN template. The next ProvisionProduct or UpdateProvisionedProduct using that version executes the
  attacker's template as the launch role bound to the product. cicd-chains propagates this CanModifyCode
  + ExecutesAs into CanExecuteAs.
match:
- - principal: null
  - CanModifyCode
  - product: null
where:
- 'node_type(?product) == BuildWorker  # AWS::ServiceCatalog::CloudFormationProduct'
- ?principal has EFFECTIVE servicecatalog:CreateProvisioningArtifact on ?product
- ?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:
  - servicecatalog:CreateProvisioningArtifact
  - servicecatalog:UpdateProvisioningArtifact?
  conditions:
  - iam_permission
  - version_active
  - run_path
  state_logic: "ACTIVE when ?principal has EFFECTIVE servicecatalog:CreateProvisioningArtifact on ?product\
    \ AND matched(optional[0]): the principal can ALSO trigger provisioning (ProvisionProduct / UpdateProvisionedProduct),\
    \ closing the run path, AND the new version becomes the active/default version (set as default via\
    \ servicecatalog:UpdateProvisioningArtifact or Active=true at creation). CONDITIONAL(run_path) when\
    \ the principal cannot directly trigger provisioning \u2014 another principal must call ProvisionProduct\
    \ to realize the escalation. CONDITIONAL(version_active) when the new version is not yet set as the\
    \ default (requires a subsequent UpdateProvisioningArtifact to activate it or an explicit version\
    \ ID at ProvisionProduct time). UpdateProvisioningArtifact is required for ACTIVE state. BLOCKED when\
    \ an SCP or permission boundary denies servicecatalog:CreateProvisioningArtifact at the effective\
    \ scope, or when the product has no LaunchRole constraint."
  confidence: 0.92
  derived_from:
  - servicecatalog:CreateProvisioningArtifact EFFECTIVE permission on ?product
  - ?product LaunchRole constraint present (RoleArn non-empty)
  - cicd-chains.yaml cicd-modify-buildspec-executes-as (consumes this CanModifyCode + ExecutesAs)
  false_positive_note: "Only emit when the product has a LaunchRole constraint. Without a launch role,\
    \ the new template version runs as the caller's own identity \u2014 no privilege gain. A new version\
    \ that is not set as active (Guidance=DEPRECATED, or not the default) will only be used if a provisioner\
    \ explicitly requests it by version ID \u2014 downgrade to CONDITIONAL(version_active) until confirmed\
    \ as the active version. servicecatalog:UpdateProvisioningArtifact is required to set the version\
    \ active; when absent, this edge stays CONDITIONAL(version_active). cicd-chains cicd-modify-buildspec-executes-as\
    \ rolls this CanModifyCode + the product's ExecutesAs(launch role) into CanExecuteAs \u2014 do NOT\
    \ re-derive CanExecuteAs here."
  narrative: '{principal.name} can add a new product version to {product.name} (servicecatalog:CreateProvisioningArtifact),
    supplying an attacker-controlled CloudFormation template. When that version is used for a future ProvisionProduct
    or UpdateProvisionedProduct, the template executes as the launch role bound to {product.name}. cicd-chains
    propagates this to CanExecuteAs.'
move · open · esc close