This issue has been assessed as high severity. Review affected configurations immediately.
Azure Storage Shared Access Signatures (SAS tokens) are everywhere. They’re used to share files with external parties, to provide CI/CD pipelines with write access to deployment artefacts, to give client applications direct read access to blob storage, and to feed data to analytics pipelines. They’re also one of the most consistently misconfigured access control mechanisms in Azure environments — and when they go wrong, the result is typically a data exposure that’s hard to detect and harder to bound.
What Makes SAS Tokens Risky
A SAS token is a URI query string appended to an Azure Storage URL that grants the holder specific permissions on a resource. Unlike managed identities or Entra ID roles, a SAS token is a bearer credential — whoever has it can use it, with no further authentication. The token encodes the permissions, expiry, and scope, and is signed with a storage account key.
This creates several structural risks:
They embed in code. SAS tokens are long query strings that look like configuration values. Developers routinely hardcode them in application configs, commit them to source control, log them in application logs, or paste them into documentation. A secret stored in code is a secret that will eventually be exposed.
They’re generated with excessive permissions. The quick path to a working SAS token is to give it full permissions (rwdlacuptfxi — read, write, delete, list, add, create, update, process, tag, filter, execute, immutability policy) and a long expiry. These defaults don’t get reviewed.
They’re not revocable individually. Account SAS tokens cannot be revoked without rotating the storage account key, which breaks every other SAS token and application using that account. Service SAS tokens tied to stored access policies can be revoked by deleting the policy, but most tokens are not configured this way.
They don’t generate principal-level audit logs. Access via SAS token is logged in Storage Diagnostic Logs, but not attributed to an identity in the way Entra ID RBAC access is. A SAS token stolen and used by an attacker looks identical to legitimate application access.
Attack Surface in the Wild
Exposed SAS tokens in repositories: GitHub secret scanning regularly finds Azure SAS tokens in public repositories. The exposure window before discovery is typically hours to days; if the token grants write access, that window is sufficient for data modification or injection.
SAS tokens in URLs: Tokens passed as URL query parameters appear in server access logs, browser history, web proxies, and CDN logs. Any system that logs HTTP requests is potentially capturing SAS tokens in plain text.
Oversharing via Storage Explorer: The Azure Storage Explorer GUI makes it trivial to generate full-permission SAS tokens with long expiry — the default settings are maximally permissive. Tokens generated this way for “quick” sharing frequently become permanent access grants.
Container-level public access: Separate from SAS tokens, storage accounts with PublicAccessEnabled on containers allow anonymous read access to all blobs in that container. This is a distinct issue but frequently found alongside SAS token problems.
Auditing Your Storage Account Exposure
Find public-access containers
# List all storage accounts and check for public access
az storage account list --query '[].{name:name,rg:resourceGroup}' -o tsv | while read name rg; do
echo "=== $name ===";
az storage container list \
--account-name "$name" \
--auth-mode login \
--query '[?properties.publicAccess != null].{name:name,access:properties.publicAccess}' \
-o table;
done
Check for account-level public access allowance
az storage account list \
--query '[].{name:name,publicAccess:allowBlobPublicAccess}' \
-o table
Any account showing True for allowBlobPublicAccess should be reviewed. In most enterprise environments, there is no legitimate reason for this to be enabled.
Find stored access policies (revocable SAS)
az storage container policy list \
--container-name <container> \
--account-name <account> \
--auth-mode login
If no policies are listed, all SAS tokens for this container are account-key-signed and cannot be individually revoked.
Hardening Guidance
1. Disable public blob access at the account level.
az storage account update \
--name <account> \
--resource-group <rg> \
--allow-blob-public-access false
Enforce this via Azure Policy (built-in definition: Storage account public access should be disallowed).
2. Enforce HTTPS-only access.
SAS tokens transmitted over HTTP are exposed in transit. Require HTTPS at the account level:
az storage account update \
--name <account> \
--resource-group <rg> \
--https-only true
3. Use stored access policies for all application SAS tokens.
Rather than bare account-key SAS tokens, create stored access policies on containers:
az storage container policy create \
--name app-read-policy \
--container-name <container> \
--account-name <account> \
--permissions r \
--expiry 2026-12-31 \
--auth-mode login
Generate SAS tokens that reference the policy:
az storage container generate-sas \
--name <container> \
--account-name <account> \
--policy-name app-read-policy \
--auth-mode login
To revoke all tokens issued under this policy, delete the policy. The tokens immediately stop working without key rotation.
4. Prefer managed identities over SAS tokens for internal application access.
Any application running in Azure (App Service, AKS, Functions, VMs) can use a managed identity to access storage via Entra ID RBAC without any credential management. This eliminates the SAS token class of risk entirely for those applications.
# Assign Storage Blob Data Reader to a managed identity
az role assignment create \
--assignee <managed-identity-principal-id> \
--role "Storage Blob Data Reader" \
--scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>
5. Set a short default expiry and enforce it via policy.
Microsoft Defender for Cloud flags SAS tokens with expiry greater than 180 days. Enforce shorter expiry in your token generation runbooks and CI/CD tooling. For application tokens backed by stored access policies, a 90-day expiry with automated renewal is a reasonable baseline.
6. Enable Microsoft Defender for Storage.
Defender for Storage detects anomalous access patterns including access from unusual geolocations, mass enumeration of blob containers, and access from known malicious IP ranges. It does not solve the SAS token architecture problem, but it provides detection coverage for exploitation of exposed tokens.
az security pricing create \
--name StorageAccounts \
--tier Standard
Detecting SAS Token Exposure
In Microsoft Sentinel, correlate storage diagnostic logs with your source control and CI/CD pipeline logs:
StorageBlobLogs
| where AuthenticationType == "SAS"
| where StatusCode == 200
| summarize
RequestCount = count(),
UniqueIPs = dcount(CallerIpAddress),
BytesRead = sum(ResponseBodySize)
by AccountName, Uri, bin(TimeGenerated, 1h)
| where RequestCount > 1000 or UniqueIPs > 10
| order by BytesRead desc
High request counts or many source IPs on a SAS-authenticated endpoint warrants investigation — either the token was exposed broadly, or an attacker is actively exfiltrating data through it.