Test tenants, old app registrations and forgotten keys keep their access long after anyone remembers why they exist, and attackers go looking for them. Microsoft's Midnight Blizzard intrusion started with a password spray on a legacy test tenant account without MFA and turned on a legacy test OAuth app that still had elevated access to the corporate environment. Storm-0558 used a 2016 consumer signing key that should have been retired. NHI Mgmt Group, The State of NHI & AI Agent Breach Report 2026 (October 2026) draws the lesson directly: test tenants and legacy app registrations need an owner, a review cycle and monitoring. This guide shows how to find these identities, decide what to keep, and retire the rest without breaking production. It is written for Entra ID, cloud and IAM administrators, with the same approach applying to other identity providers.
Key takeaways
- Non-production is not low risk when it trusts production. The Midnight Blizzard test app reached corporate mailboxes because it held access in the corporate tenant.
- Legacy means unowned, unreviewed and unmonitored. The weakness is the missing lifecycle, not the age of the app.
- Old credentials stay valid until someone acts. Storm-0558's key should have been retired in March 2021 and was still accepted in 2023.
- Application sign-ins skip MFA by design. The ConnectWise 2026 case showed a stolen app secret signing in to customer tenants with no user involved.
- Retire in stages. Disable, watch, then delete, with a rollback window, so cleanup does not become an outage.
Why test tenants and legacy apps become breach sources
- Weaker sign-in rules: test tenants often lack the conditional access, MFA and password protection applied to production. Midnight Blizzard's entry account had no MFA.
- Cross-environment trust: an app registered in a test tenant can be multi-tenant and consented in production, or a test service principal can be granted roles in the production tenant.
- Broad application permissions: application permissions such as Exchange Online
full_access_as_appwork without a signed-in user, so the app's credential is all an attacker needs. - Long-lived secrets: client secrets and certificates added years ago, never rotated, sometimes with no expiry.
- No owner: the engineer who created it has moved on, so nobody receives alerts or reviews it.
- Thin logging: test tenants may not stream sign-in and audit logs to the SIEM.
The report shows how often app identities feature in breaches: OAuth tokens were abused in 20 breaches, service accounts in 30, and OAuth or SaaS integration was the route in for 15.
Three cases, one missing lifecycle
| Breach | The forgotten identity | What it allowed | What was missing |
|---|---|---|---|
| Microsoft Midnight Blizzard 2024 | A legacy, non-production test tenant account without MFA, and a legacy test OAuth app with elevated access to the corporate environment | The actor created malicious OAuth apps and a new user to consent to them, granted the full_access_as_app role and read email from a small percentage of corporate mailboxes, including senior leadership | MFA on the test account; removal of test-to-corporate trust; owner and review of the legacy app; alerts on app role grants |
| Microsoft Storm-0558 2023 | A 2016 Microsoft account consumer signing key that the CSRB found should have been retired in March 2021, after manual rotation stopped | With a validation flaw, forged tokens were accepted for enterprise mail; more than 500 people at 22 organisations had mail read | Key retirement on schedule; alerting on old, active keys; scope validation of issuer |
| ConnectWise Cloud Backup 2026 | A vendor multi-tenant app with a client secret and tenant-wide mail, file and Teams permissions | The stolen secret signed in to customer tenants through the client credentials flow; 162 tenants had confirmed unauthorised sign-ins in Huntress's base, and related service principals assigned themselves directory roles in about 50 | Customer-side review of consented vendor apps and their permissions; alerts on service principals adding roles or secrets |
The Cloudflare response to its 2023 intrusion included physical segmentation of test and staging systems, a sign of how far non-production can reach. See the Cloudflare breach page.
Find them: an inventory pass
- List every tenant you own. Include test, demo, developer, sandbox and acquired tenants. Check billing records, domain registrations and admin accounts held by engineers. A tenant nobody lists is the first finding.
- Export app registrations and service principals in each tenant. Record app ID, display name, sign-in audience (single or multi-tenant), owners, created date, credentials (type, start and end dates) and permissions granted. Separate first-party, your own and third-party apps.
- Find cross-tenant reach. For apps registered in non-production tenants, check whether a service principal for the same app ID exists in production, and what it has been granted there.
- Pull last activity. Use service principal sign-in logs in Entra ID (separate from interactive user sign-ins) to find last sign-in per app. No sign-in in 90 days is a dormancy candidate. See How to find and remove stale service principals in Entra ID.
- Flag high-risk permissions. Application permissions on mail, files, directory write and role management, Exchange
full_access_as_appandApplicationImpersonation. Microsoft's Midnight Blizzard responder guidance names these for review. See How to review Microsoft 365 app registrations with mail permissions. - Find non-production accounts without MFA. Report every enabled account in test tenants that is not covered by MFA or conditional access.
Decide: keep, fix or retire
| Finding | Decision | Action |
|---|---|---|
| No owner, no sign-in in 90 days | Retire | Disable sign-in, watch for 30 days, then delete the app and its service principals |
| No owner, still signing in | Fix urgently | Trace the calling workload from sign-in logs, assign an owner within two weeks, or disable |
| Test app with permissions in production | Fix or retire | Remove the production grant; if production needs it, register a separate production app with its own owner |
| High-risk application permission | Fix | Reduce to the narrowest permission; scope Exchange application access to specific mailboxes with RBAC for applications |
| Client secret with long or no expiry | Fix | Move to a certificate or federated credential; set short lifetimes |
| Third-party multi-tenant app nobody uses | Retire | Revoke consent and delete the service principal |
| Test tenant with no current purpose | Retire | Remove apps and accounts, then close the tenant |
Small vs large: a small organisation with one tenant and a few dozen apps can do this in a single review. A large one with many tenants should first remove cross-tenant trust and high-risk permissions, which cuts the worst paths, then work through dormancy in waves by business unit.
Retire safely: the rollout
- Announce and assign: publish the list of candidate apps to engineering with a two-week window to claim ownership.
- Disable, do not delete: disable sign-in for the service principal first. This is reversible.
- Watch: monitor service principal sign-in failures and help desk tickets for 30 days. A failure names the workload that still depended on the app.
- Remove credentials: delete client secrets and certificates from apps that stay disabled, so re-enabling cannot silently restore old access.
- Delete: remove the app registration and service principals. Entra ID keeps deleted app registrations recoverable for a period, which is the final rollback.
- Roll back: if a business process breaks, re-enable under a named owner with a fix-by date, rather than restoring the old state indefinitely.
Prevent new legacy: guardrails
- App management policies: in Entra ID, tenant-wide and per-app policies can block new password secrets (
passwordAddition), cap secret lifetime (passwordLifetime), block custom passwords (customPasswordAddition), cap certificate lifetime (asymmetricKeyLifetime), restrict certificates to trusted issuers and block multi-tenant registrations through theaudiencesrestriction. - Owner required: every app needs at least two named owners, checked in a regular attestation. See the NHI Ownership Attestation Campaigns Guide.
- Same sign-in baseline in every tenant: MFA, legacy authentication blocked and password protection in test tenants too.
- No test-to-production trust: separate apps per environment; production consent only for apps registered for production.
- Expiry by default: test apps get an end date at creation and are disabled when it passes.
- Logs from every tenant: stream sign-in and audit logs from non-production tenants to the same SIEM.
- Key retirement tracking: for signing keys you own, track creation and planned retirement, and alert on keys past their date, the gap the CSRB found in Storm-0558.
For consent policy and admin consent workflow see the Entra ID Applications and Consent Guide, and for secrets on apps the Azure Entra Client Secrets Security Guide.
Detection and measurement
| Signal | Where to look | Why it matters |
|---|---|---|
| New secret or certificate added to an existing app | Entra audit log, update application or service principal credentials | Attackers add their own credential to an existing app (ATT&CK T1098.001); ConnectWise's attacker added secrets to two other apps |
| New application role assignment or admin consent | Entra audit log, consent and app role assignment events | Midnight Blizzard granted full_access_as_app this way |
| Service principal added to a directory role | Entra audit log, add member to role | ConnectWise service principals gave themselves roles |
| Dormant app signs in again | Service principal sign-in logs against your dormancy list | A forgotten app waking up is a strong signal |
| Spike in mailbox API calls after a credential change | Exchange and cloud app audit events | Named in Microsoft's Midnight Blizzard responder guidance |
| Password spray on test tenant accounts | Sign-in logs of non-production tenants | The Midnight Blizzard entry point |
Metrics:
- Apps without two named owners (target: zero).
- Apps with no sign-in in 90 days still enabled.
- Non-production apps or service principals holding production permissions (target: zero).
- Client secrets with lifetime above your policy limit.
- Non-production tenants streaming logs to the SIEM, as a share of all tenants.
- Enabled test tenant accounts without MFA (target: zero).
Common failure patterns
- Treating test tenants as out of scope: Midnight Blizzard's entry was a test tenant account.
- Reviewing users but not apps: access reviews that skip service principals miss the identities that need no MFA.
- Keeping keys past retirement: Storm-0558's key outlived its planned life by two years.
- Trusting vendor apps without review: a consented multi-tenant app holds whatever was granted, as ConnectWise customers found.
- Deleting first: deleting without a disable and watch period causes outages and makes teams resist the next cleanup.
Framework mapping
| Framework | Reference | How it applies |
|---|---|---|
| NIST CSF 2.0 | ID.AM-02, PR.AA-01, PR.AA-05 | Inventory of services and apps; credential management; least privilege for apps. |
| NIST SP 800-53 Rev 5 | AC-2, IA-4, IA-5, CM-8, SC-12 | Account and identifier lifecycle, authenticators, inventory, key management. |
| MITRE ATT&CK v20 | T1110.003, T1078.004, T1098.001, T1550.001 | Password spraying, cloud accounts, additional cloud credentials, application access tokens. |
Practitioner checklist
- List every tenant you own, including test, demo, sandbox and acquired tenants.
- Export apps and service principals with owners, credentials, permissions and last sign-in.
- Remove production permissions held by non-production apps.
- Apply MFA and conditional access to every account in test tenants.
- Reduce high-risk application permissions and scope mailbox access with RBAC for applications.
- Retire unowned, dormant apps in stages: disable, watch, remove credentials, delete.
- Set app management policies to cap secret lifetimes and block new secrets where possible.
- Alert on new app credentials, app role grants, consents and service principals added to roles.
- Stream sign-in and audit logs from all tenants to the SIEM.
Standards and references
- Microsoft Threat Intelligence: Midnight Blizzard, guidance for responders on nation-state attack
- Microsoft Learn: Configure app management policies
- Microsoft Learn: Sign-in logs in Microsoft Entra ID
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
- MITRE ATT&CK: T1098.001 Additional Cloud Credentials
- NHI Mgmt Group: The State of NHI & AI Agent Breach Report 2026 (October 2026)
Related NHI Mgmt Group resources: Entra ID Applications and Consent Guide · NHI Offboarding and Decommissioning Guide · NHI Dormancy Detection · Non-Human Identity (NHI) Guide