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.

derived aws emits CanModifyCode

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 typeIdentity
target typeArtifactRepository
source?principal
target?downstream_repo
permissionscodeartifact:PublishPackageVersion codeartifact:GetAuthorizationToken
conditionsiam_permission resource_policy
state logicInherit 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.'
move · open · esc close