Cut-paper illustration: a layered paper cloud above a server rack, a paper key snapped in half, paper storage disks falling away, and a paper stopwatch — representing compromised service-principal credentials destroying cloud resources against the clock

On September 25, Microsoft Security Research published a detailed incident report about Storm-3168 — the actor it links to JADEPUFFER, the "agentic ransomware" crew Sysdig documented in July. The headline fact is grim: two compromised Azure service principals, one tenant, roughly seven minutes of automated destruction, and more than 100 storage-account deletion attempts, most of them successful. A Key Vault, a Function App, and an App Service plan went with them.

It would be easy to read that as a story about exotic attackers. It's not. Every failure in this incident was an ordinary, fixable, unglamorous one: a long-lived client secret, overly broad role assignments, and guardrails that were never turned on. The durable lesson has nothing to do with AI. It's about machine identities — the ones nobody rotates and everybody trusts.

What actually happened

The timeline, straight from Microsoft's report, shows a patient operation followed by a very fast one:

Phase What Microsoft observed
Recon (early June 2026) Service principal #1 enumerated VMs, subscriptions, and resource groups for ~15.5 hours — 300+ successful read operations
Fast discovery ~90 minutes later, service principal #2 enumerated VMs and resource groups across two subscriptions in five seconds
Credential hunting 16 hours later, #2 enumerated App Service configuration stores (likely hunting exposed credentials) and probed a non-existent storage account with ListKeys
Destruction (~7 min) 100+ storage-account deletion attempts in about seven minutes — most succeeded; Key Vault, Function App, and App Service plan deleted
Key collection ~30 minutes later, 30+ successful ListKeys requests against surviving storage accounts, including Site Recovery–related ones

Everything ran through the identities' existing Azure RBAC permissions. No privilege escalation exploit, no zero-day. A group-granted Storage Account Contributor role authorized the storage deletions. Direct Contributor authorized the app-resource deletions and the key retrieval. Direct SQL DB Contributor authorized parallel SQL database deletion attempts — which failed, because the attacker used an unsupported API version for the Azure SQL resource type. Sometimes a compatibility problem is a control.

What actually held the line

This is the part worth dwelling on, because it reads like a checklist of boring things that work:

  • Azure resource locks and storage account–level deletion protection blocked some of the deletion attempts. Microsoft's own phrasing: these "remain effective even when a compromised identity has broad administrative permissions." The lock plane is separate from the identity plane. That's the whole point.
  • Attempts to remove Azure Site Recovery locks and Azure Backup protection locks failed. The attacker tried to strip recovery protections and couldn't.
  • Removing or redacting an exposed secret does not invalidate it. One of the compromised principals had its client ID, client secret, and tenant ID posted in plaintext in a public GitHub issue by an employee of the victim org. Someone edited the issue to delete the secret — but it stayed in the public edit history. Microsoft is explicit: treat anything ever exposed as compromised and rotate it. Editing the post fixes the optics, not the exposure.

Notice what isn't on that list: any AI magic. Microsoft's evidence for orchestration is "strongly indicates automated or scripted execution" — division of labor across identities, overlapping token streams, rapid sequencing, and a python-requests/2.34.2 user agent. As Swimlane's Nick Tausek told Dark Reading, the Azure evidence shows coordinated automation rather than proving an AI model directed each step. I don't care who or what drove the loop. The outcome was decided by permissions, locks, and secret hygiene — inputs fully within the defender's control either way.

The uncomfortable parts

Microsoft could not confirm how the service principals were initially compromised. The exposed GitHub credentials might be the entry point; Microsoft says it couldn't confirm it. That's honest, and it should make you slightly uneasy: an environment can hold that much standing destructive permission on two identities without anyone being sure which secret leaked.

Also worth noting: Storm-3168 infrastructure has been probing Azure App Services across multiple customers since the beginning of the year — WordPress admin paths, PHP-CGI, LangFlow's /api/v1/validate/code endpoint, other web-shell-like paths. Microsoft found no App Service–to–ARM credential path for this tenant, but the probing means other tenants are on the list. Patching your internet-facing apps is part of this story too.

And the end state: Microsoft assesses the activity as ransomware-aligned — destruction plus targeting of recovery controls plus key collection — but observed no ransom note and confirmed no data exfiltration. Don't file this under "wouldn't happen to us because we're too small to extort." The motive barely matters when the mechanics work on anyone.

This week's service-principal checklist

You don't need a new product for any of this. You need an inventory and a Thursday afternoon.

  1. Inventory every service principal with standing secrets. In Entra, list app registrations and service principals; flag client secrets with expiry beyond 90 days or no expiry. Long-lived secret = standing key to everything that identity can touch.
  2. Check effective permissions, including group grants. The destructive storage role here arrived via group membership, not direct assignment. Review with effective-access in mind — direct, group-inherited, and management-group-inherited.
  3. Verify least privilege on the top-risk ones. Anything holding Contributor, Storage Account Contributor, or Key Vault roles should justify it in writing. "The app needed it two years ago" is not justification.
  4. Put Delete locks on production resource groups and storage accounts. This is the control that demonstrably worked. It costs nothing and survives a compromised identity.
  5. Turn on storage account–level deletion protection where the platform offers it — a second, independent latch.
  6. Separate the recovery plane. Backup and recovery resources should not be administrable by the same identities that run production. The attacker tried to strip Site Recovery and Backup locks and failed — keep it that way by design.
  7. Rotate anything that was ever exposed — anywhere. Issue edited, repo deleted, message unsent: irrelevant. Rotate, then investigate historical use via sign-in and audit logs.
  8. Prefer managed identities and workload identity federation over stored client secrets wherever the workload supports it. No stored secret, nothing to paste into a GitHub issue.
  9. Alert on the observable behaviors. Watch for unusual ListKeys volume, bulk delete operations, and service-principal sign-ins from unfamiliar IPs in Entra audit logs and Defender for Cloud.

Microsoft also recommends enabling Defender for Cloud workload protections (Resource Manager, Storage, Key Vault, App Service, Databases) — worth doing, but note it would have detected this attack; the locks stopped parts of it. Detection and prevention are different line items on the checklist.

Sources

The boring conclusion

Two machine identities with stale secrets and broad roles deleted a tenant's storage in seven minutes. Everything that stopped them — locks, deletion protection, failed API calls, failed lock-removal attempts — was boring, old, and already available in the portal. The AI-orchestration debate is interesting and mostly irrelevant to your to-do list. Inventory the non-human identities, narrow their permissions, lock the resources, rotate the secrets. That was the whole game, and it still is.