aws-ca-upstream-propagation
Publishing to an upstream repository propagates CanModifyCode to every downstream repository in the upstream chain whose consumers resolve packages through it.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanModifyCode {'upstream_repo': None}
{'downstream_repo': None} ContainsResourceReference {'upstream_repo': None}
where
node_type(?upstream_repo) ==
ArtifactRepository
node_type(?downstream_repo) == ArtifactRepository
provider_type(?upstream_repo) in [AWS::CodeArtifact::Repository, AWS::CodeArtifact::Package]
provider_type(?downstream_repo) == AWS::CodeArtifact::Repository
reference_kind(?downstream_repo -> ?upstream_repo) == upstream_repository
?upstream_repo != ?downstream_repo
emit
| source type | Identity |
|---|---|
| target type | ArtifactRepository |
| source | ?principal |
| target | ?downstream_repo |
| permissions | codeartifact:PublishPackageVersion codeartifact:GetAuthorizationToken |
| conditions | iam_permission resource_policy |
| state logic | Inherit state from the contributing CanModifyCode(?principal -> ?upstream_repo): if that edge is ACTIVE and the upstream relationship is confirmed (the downstream repo's upstreams[] list contains upstream_repo), emit ACTIVE — a package published to upstream_repo will be served to consumers of downstream_repo when not found locally. CONDITIONAL(package_name_collision) when no specific name collision between the attacker's package and a package expected by downstream consumers is confirmed — the resolution only occurs if the attacker's package name matches one that the consumer requests. BLOCKED if the contributing CanModifyCode is BLOCKED, or if the downstream repository has an explicit DENY on inbound package resolution from upstream_repo (uncommon but possible via package-origin-control). |
Narrative
{principal.name} can publish to {upstream_repo.name}, which is configured as an upstream of {downstream_repo.name}. A package version published to {upstream_repo.name} will be resolved by consumers of {downstream_repo.name} when the package is not found locally, injecting attacker-controlled code into those consumers' build or runtime environments.
Raw rule rules/derived/aws/codeartifact.yaml
id: aws-ca-upstream-propagation
emits: CanModifyCode
description: Publishing to an upstream repository propagates CanModifyCode to every downstream repository
in the upstream chain whose consumers resolve packages through it.
match:
- - principal: null
- CanModifyCode
- upstream_repo: null
- - downstream_repo: null
- ContainsResourceReference
- upstream_repo: null
where:
- node_type(?upstream_repo) == ArtifactRepository
- node_type(?downstream_repo) == ArtifactRepository
- provider_type(?upstream_repo) in [AWS::CodeArtifact::Repository, AWS::CodeArtifact::Package]
- provider_type(?downstream_repo) == AWS::CodeArtifact::Repository
- reference_kind(?downstream_repo -> ?upstream_repo) == upstream_repository
- ?upstream_repo != ?downstream_repo
emit:
source_type: Identity
target_type: ArtifactRepository
source: ?principal
target: ?downstream_repo
permissions:
- codeartifact:PublishPackageVersion
- codeartifact:GetAuthorizationToken
conditions:
- iam_permission
- resource_policy
state_logic: "Inherit state from the contributing CanModifyCode(?principal -> ?upstream_repo): if that\
\ edge is ACTIVE and the upstream relationship is confirmed (the downstream repo's upstreams[] list\
\ contains upstream_repo), emit ACTIVE \u2014 a package published to upstream_repo will be served\
\ to consumers of downstream_repo when not found locally. CONDITIONAL(package_name_collision) when\
\ no specific name collision between the attacker's package and a package expected by downstream consumers\
\ is confirmed \u2014 the resolution only occurs if the attacker's package name matches one that the\
\ consumer requests. BLOCKED if the contributing CanModifyCode is BLOCKED, or if the downstream repository\
\ has an explicit DENY on inbound package resolution from upstream_repo (uncommon but possible via\
\ package-origin-control)."
confidence: 0.75
derived_from:
- ?principal CanModifyCode ?upstream_repo
- ?downstream_repo ContainsResourceReference ?upstream_repo (upstream_repository)
false_positive_note: "Upstream propagation only reaches consumers that request a package name that exists\
\ in upstream_repo (or could be published there by the attacker) and is NOT already present in downstream_repo\
\ or a higher-priority upstream. If downstream_repo already has a pinned, immutable version of every\
\ package the attacker could publish, the propagation does not reach the consumer \u2014 downgrade\
\ to CONDITIONAL. AWS CodeArtifact introduced BLOCK origin-control in 2023: if the downstream repo\
\ has package origin control set to BLOCK for the upstream, new versions from that upstream cannot\
\ be ingested -> emit BLOCKED for that combination. This rule does not re-derive the consumer-level\
\ CanModifyCode or CanExecuteAs \u2014 container-chains image-push-poisons-consumers consumes this\
\ CanModifyCode and fans out to each consuming workload via ContainsResourceReference(consumer ->\
\ downstream_repo)."
narrative: '{principal.name} can publish to {upstream_repo.name}, which is configured as an upstream
of {downstream_repo.name}. A package version published to {upstream_repo.name} will be resolved by
consumers of {downstream_repo.name} when the package is not found locally, injecting attacker-controlled
code into those consumers'' build or runtime environments.'