Azure SAS Tokens That Outlive Key Rotation
An Azure Storage account SAS minted with account-wide scope keeps working after a scheduled key rotation, because rotation runbooks routinely regenerate only key1 while the token was signed with key2, and no stored access policy exists to revoke it independently. RBAC and firewall rules never see the request, since SAS bypasses Azure AD authorisation entirely.
At a glance
- Unsafe setting
- Account SAS tokens are generated with account-wide scope and signed by a storage key that scheduled rotation never touches.
- Failure trigger
- A leaked or forgotten account SAS token, signed with the idle key, remains valid after the routine key1 rotation completes.
- Blast radius
- Possession of the token grants read, write and delete across every blob container, queue, table and file share in the account, unconstrained by RBAC.
- Recommended control
- Replace account-scoped SAS with Azure AD-backed user delegation SAS or stored-access-policy Service SAS, and rotate key1 and key2 together.
The Trap
Account SAS Tokens Signed With the Idle Storage Key
The Default State
The Azure Portal’s “Shared access signature” blade, under Storage Account > Security + networking, defaults the “Signing key” dropdown to key1 and the “Allowed services” checkboxes to Blob, File, Queue and Table simultaneously, with “Allowed resource types” set to Service, Container and Object all ticked. Combined with permissions left at the portal default of Read, Write, Delete, List, Add, Create, Update and Process, this produces an Account SAS with account-wide reach rather than the narrower Service SAS scoped with sr=c to one container. Engineers scripting SAS generation via az storage account generate-sas or the .NET AccountSasBuilder inherit the same account-level defaults unless srt and ss are explicitly restricted, and the token is bound to whichever key the CLI or SDK selects, key1 by convention, with no reference to a stored access policy at all.
The Blast Radius
Revocation of any SAS token that is not built from a stored access policy has exactly one mechanism: invalidate the signing key itself via az storage account keys renew. Rotation runbooks and Key Vault rotation policies almost always target key1 on a fixed schedule because it is the key referenced in application connection strings, and leave key2 untouched for months because nothing consumes it directly. An account SAS minted from key2 during a pipeline debug session, a support escalation, or a leaked CI variable therefore survives every scheduled key1 rotation indefinitely. Because the token carries account-level scope (ss=bqtf, srt=sco), possession of it grants read, write and delete across every container, queue, table and file share in the account, not just the resource the original task required, turning a single forgotten debug token into full data-plane compromise that no key1 rotation, firewall rule or RBAC assignment touches.
The Lead Mechanic Fix
Stop issuing Account SAS tokens for anything short-lived. Replace them with a User Delegation SAS, signed by an Azure AD token rather than an account key, generated with az storage container generate-sas –auth-mode login –as-user –account-name <name> –name <container> –permissions rwdl –expiry <date>. This token cannot outlive Azure AD credential rotation and has a hard maximum lifetime of seven days regardless of the expiry field set. Where a Service SAS must be used, bind it to a stored access policy with az storage container policy create –account-name <name> –container-name <container> –name <policy> –permissions rd –expiry <date>, so revocation is a single az storage container policy update call rather than a full key rotation. Finally, enforce paired key rotation: rotate key1 and key2 in the same maintenance window with az storage account keys renew –key key1 –key key2, closing the gap where one key sits unrotated while account SAS tokens signed against it remain valid.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Replace account-scoped SAS with Azure AD-backed user delegation SAS or stored-access-policy Service SAS, and rotate key1 and key2 together.
Validate the vendor-specific syntax in official documentation before applying it.
Verify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.