azure-acr-task-write
tasks/write over an ACR Task - 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. |
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).'