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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
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).
CanTrigger {'product': None}
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 — 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.'