azure-acr-task-write

tasks/write over an ACR Task - modifies build steps (the BuildWorker's code) that run as the task's MI.

derived azure emits CanModifyCode

match (effective permission)

{ "action": "Microsoft.ContainerRegistry/registries/tasks/write", "scope_type": "resource|resourceGroup|subscription" }

where

principal effectively holds Contributor, Owner, or a custom role including Microsoft.ContainerRegistry/registries/tasks/write at the scope the target task has an ExecutesAs managed identity (system-assigned or user-assigned)

emit

source typeIdentity
target typeBuildWorker
source<principal>
target<task (BuildWorker)>
permissionsMicrosoft.ContainerRegistry/registries/tasks/write
state logicACTIVE when the principal can update the task definition and a task run will subsequently occur (existing timer/base-image trigger, or the attacker can also trigger runs via tasks/runs/write). CONDITIONAL(trigger_exists) when no scheduled trigger exists and the attacker lacks tasks/runs/write to trigger manually.

Narrative

{principal.name} can overwrite the build steps of ACR Task {target.name} (registries/tasks/write); the next run will execute the modified steps as the task's managed identity (cicd-chains rolls this into CanExecuteAs of the task MI).

Raw rule rules/derived/azure/acr.yaml

id: azure-acr-task-write
emits: CanModifyCode
description: "tasks/write over an ACR Task \u2014 modifies build steps (the BuildWorker's code) that run\
  \ as the task's MI."
match_effective_permission:
  action: Microsoft.ContainerRegistry/registries/tasks/write
  scope_type: resource|resourceGroup|subscription
where:
- principal effectively holds Contributor, Owner, or a custom role including Microsoft.ContainerRegistry/registries/tasks/write
  at the scope
- the target task has an ExecutesAs managed identity (system-assigned or user-assigned)
emit:
  source_type: Identity
  target_type: BuildWorker
  source: <principal>
  target: <task (BuildWorker)>
  permissions:
  - Microsoft.ContainerRegistry/registries/tasks/write
  state_logic: ACTIVE when the principal can update the task definition and a task run will subsequently
    occur (existing timer/base-image trigger, or the attacker can also trigger runs via tasks/runs/write).
    CONDITIONAL(trigger_exists) when no scheduled trigger exists and the attacker lacks tasks/runs/write
    to trigger manually.
  confidence: 0.93
  derived_from:
  - "cicd-chains buildspec-execute-as (CITED \u2014 rolls CanModifyCode(task) + ExecutesAs(task\u2192\
    MI) into CanExecuteAs)"
  false_positive_note: "Only security-relevant when the task has an ExecutesAs MI \u2014 if no identity\
    \ is bound (identity.type None and no userAssignedIdentities), the task runs without an ARM credential\
    \ and code injection yields only build-environment access (lower value; still emit but lower confidence).\
    \ cicd-chains handles the CanExecuteAs derivation; do NOT duplicate it here. The trigger gate matters:\
    \ tasks/write alone doesn't run the task \u2014 a trigger or tasks/runs/write is needed to realize\
    \ execution."
  narrative: '{principal.name} can overwrite the build steps of ACR Task {target.name} (registries/tasks/write);
    the next run will execute the modified steps as the task''s managed identity (cicd-chains rolls this
    into CanExecuteAs of the task MI).'
move · open · esc close