Here’s the part nobody wants to say out loud: the attackers didn’t break anything. They logged in. The credential was valid, the permissions were real, and Azure did exactly what it was told. That’s the whole story of the JADEPUFFER-linked intrusions, and it’s the same story we’ve been telling since the first leaked AWS key in a public bucket.
Let me build this up from nothing, because the mechanism matters more than the codename.
What a service principal actually is
Azure has two kinds of identity: people and robots. A user is you, signing in with a password and ideally a second factor. A service principal is a robot account — an identity for a script, a pipeline, or a third-party tool that needs to do things in Azure without a human present. It authenticates with either a client secret (a long password) or a certificate.
Don’t confuse this with a managed identity, which is a service principal Azure manages for you — no secret to leak because the platform hands out short-lived tokens behind the scenes. That distinction is the entire point of this article, so hold onto it.
The problem with a plain service principal is the secret. It’s a string. Strings get copied. They end up in .env files, in CI variables, in a config.json someone pasted into a repo “temporarily” in 2023. And a service principal secret, by default, can live for a year or two. Plenty of time.
The role is the blast radius
A credential on its own does nothing. What makes it dangerous is the Azure RBAC role attached to it. Two roles do most of the damage in incidents like this:
- Contributor — can create, modify, and delete almost any resource. Cannot hand out new permissions. This is the role everyone over-grants because it’s easy.
- Owner — Contributor, plus the ability to assign roles to others. If the compromised principal is Owner, the attacker can grant themselves persistence.
Scope multiplies it. A Contributor assignment at the subscription or management group level means one leaked string can delete every resource group underneath it. That is how a single credential turns into an outage across multiple subscriptions: the role was broad and the scope was broader.
Deletion is the cheap attack. No data to exfiltrate, no ransomware to deploy — just az group delete in a loop. Storage accounts, VMs, databases, the lot. If soft-delete and resource locks aren’t on, it’s gone.
Find out if it’s happening to you
Everything a service principal does lands in the Azure Activity Log. Deletions and new role assignments by a non-human caller are the two signals worth hunting. In Log Analytics / Sentinel:
A burst of deletes from a Caller that’s an app ID, outside a normal deployment window, is your incident. Watch role assignments too — Microsoft.Authorization/roleAssignments/write from a service principal is almost never legitimate. Defender for Cloud and the Microsoft Threat Intelligence analytics rules flag anomalous service principal behavior, but the Activity Log query above is free and immediate.
What to actually do
First, see who holds the keys to the kingdom. List every service principal with Owner or Contributor at subscription scope:
Review it by hand — do not bulk-strip permissions, because you will break a pipeline and you won’t know which one. Right-size each to a custom role or a narrower scope. Rotate secrets on anything suspect:
Then fix the actual disease. The reason this keeps happening is that secrets exist at all. Workload Identity Federation removes them: your GitHub Actions or Azure DevOps pipeline presents its own OIDC token, Entra trusts it, and no password is ever stored.
No secret in the pipeline, nothing to commit, nothing to leak. That’s the fix that would have made JADEPUFFER a non-event.
We’ll relearn this again under a new codename in eighteen months. The credential that kills you is the one you forgot you issued.
