Skip to main content
Back to the Azure Footguns Database
GovernanceSecurityMediumCommonAZF-0103

An Azure Policy exemption expiring in days either re-arms a deny policy overnight or quietly becomes permanent

Azure Policy exemptions carry an optional expiresOn date and nothing in Azure warns anyone as it approaches. The exempted scope re-arms silently, or the exemption is renewed without review, or it expires and lingers as a dead object.

Footgun ID
AZF-0103 (Azure Footgun No. 103)
Azure service
Azure Policy
Resource type
Microsoft.Authorization/policyExemptions
Updated
October 28, 2026

What it is

An Azure Policy exemption whose expiresOn is a few days away and has no owner watching it. Exemptions are the sanctioned way to carve a resource, resource group, subscription, or management group out of a policy assignment, and the expiry date is what makes the carve-out temporary. When the date arrives, one of two things happens, and both are bad: the exempted scope silently falls back under a deny or audit effect and deployments or compliance break overnight, or someone reflexively pushes the date out to stop the bleeding and the "temporary" waiver turns into a permanent hole. Expired exemptions also stay behind as objects, so audits keep finding carve-outs that no longer do anything.

Impact (governance)
An exempted scope snaps back to deny or audit with no warning, or a 30-day waiver on a security guardrail is extended unreviewed and becomes permanent
Basis: Azure behavior (authored assessment). Figures are estimates, not measurements.

Why it happens

Azure treats expiresOn as a static property, not an event. There is no built-in notification when an exemption is about to lapse, no event when it does, and no Advisor or Defender recommendation about it. The person who approved "30 days for the migration" is never told the 30 days are up, and the exemption object itself is a small resource at an obscure scope that nobody browses.

Two edges of the same footgun make it worse. First, expiresOn is optional: many exemptions are created without one, especially from the portal under time pressure, which turns a Waiver (Azure's own definition: "the non-compliance state of the resource is temporarily accepted") into an indefinite one. Second, when the date is set and does pass, Microsoft documents that the exemption is not deleted; the object is preserved for record-keeping and simply stops being honored. So the Policy blade and az policy exemption list keep showing exemptions that are in force next to ones that expired a year ago, with nothing but a date column to tell them apart.

The security angle is the sharpest. A Waiver on a deny policy (no public storage endpoints, no VMs without disk encryption, required private endpoints on Key Vault) is a deliberate gap in a guardrail. A Mitigated exemption claims the intent is met another way; a Waiver admits it is not. Either way the reviewer accepted the gap for a bounded window, and the window closing with no review means the next decision about that gap is made by whoever is on call when a pipeline fails.

What it costs / blast radius

The direct cost is nothing; exemptions are free and so is letting them lapse. The blast radius is operational and governance harm, and it depends on which way the lapse breaks. (Azure behavior; authored assessment.)

If the exemption expires unnoticed, a deny policy re-arms against a scope that still depends on the carve-out: redeploys fail with a policy violation, the next deployment triggers DeployIfNotExists effects, and compliance scores drop across every dashboard at once. The scope can be a whole management group, which means every subscription under it inherits the surprise.

If the exemption is extended unreviewed, the guardrail stays open for another cycle with the original justification long stale. That is how a three-month waiver for a vendor appliance becomes a permanent exception that survives the appliance itself, and how an auditor ends up asking why a "temporary" exemption on an encryption policy is on its fourth year.

Either way the expired-but-present objects accumulate, and an exemption inventory that mixes live, lapsed, and permanent entries is one that no reviewer trusts.

See it

Find them: exemptions expiring within 30 days, already expired, or set to never expire
// Exemptions live in the policyresources table, not resources.
// properties.expiresOn is optional and null for permanent exemptions.
policyresources
| where type == 'microsoft.authorization/policyexemptions'
| extend expiresOn = todatetime(properties.expiresOn)
| extend status = case(
isnull(expiresOn), 'no expiry (permanent)',
expiresOn <= now(), 'EXPIRED, object still present',
expiresOn <= now(30d), 'expires within 30 days',
'later')
| where status != 'later'
| project name, displayName = tostring(properties.displayName),
category = tostring(properties.exemptionCategory),
status, expiresOn,
scope = substring(id, 0, indexof(tolower(id), '/providers/microsoft.authorization/policyexemptions')),
assignment = tostring(properties.policyAssignmentId)
| order by expiresOn asc
Fix: re-justify and extend with a reviewed date, or delete it so the guardrail applies again
# Option A: the carve-out is still needed. Extend it with a date someone
# can defend, and write the review into the description so the next
# reviewer sees why, not just when.
az policy exemption update --name waiver-legacy-storage-tls \
--scope /subscriptions/<subscriptionId>/resourceGroups/rg-legacy \
--expires-on 2027-01-31T00:00:00Z \
--description "Reviewed 2026-10-28: TLS 1.0 clients retire Jan 2027 (OPS-4412)"

# Option B: the need has passed (or it already expired). Remove the object
# so the policy applies again and the inventory stops lying.
az policy exemption delete --name waiver-legacy-storage-tls \
--scope /subscriptions/<subscriptionId>/resourceGroups/rg-legacy

How StratoLens helps

StratoLens tracks every policy exemption across every subscription and management group in your tenant, buckets them by time to expiry (expired, 30, 60, 90 days, no expiry), and sends a Policy Exemption Expiration alert when one enters your warning window, once per exemption and deadline, re-armed if the date is extended. The reviewer who approved the carve-out hears about it before the guardrail re-arms, not after the pipeline fails.

Start your 14-day free trial

Every feature unlocked. Deploys to your Azure tenant. No data leaves your tenant.

When the 14 days end, billing starts on your Azure invoice at your tier. One toggle in Settings turns it off, any time.