A single publicly exposed appsettings.json file—the standard configuration artifact in ASP.NET Core applications—can hand attackers the keys to an entire Azure Entra ID tenant. By extracting ClientId and ClientSecret pairs from the file, adversaries exchange them for OAuth 2.0 tokens and then pillage Microsoft Graph APIs without ever needing a password or multi-factor authentication. The attack is fully automatable, occurs at internet scale within minutes, and has been observed in multiple independent incident reports over the past year.

Security researchers and industry publications have documented the same pattern repeatedly: a misconfigured web root, a public GitHub commit, or an unprotected object storage bucket exposes appsettings.json. Inside, plaintext entries like "AzureAd:ClientId" and "AzureAd:ClientSecret" are trivially readable. Automated bots constantly scan for files matching that name and JSON keys that smell like secrets. Once harvested, the credentials fuel scripted attack chains that request application-only access tokens via the OAuth 2.0 client credentials grant and then query Microsoft Graph endpoints for user lists, groups, mail, and administrative roles.

The vulnerability is not a novel protocol flaw. It is an operational failure that persists because of developer convenience, inadequate CI/CD guardrails, and legacy deployment patterns. This article breaks down exactly how the exposure works, the blast radius of leaked app secrets, detection signals defenders must watch, and the concrete steps Azure tenant owners must take immediately.

How a Simple Config File Becomes a Master Key

appsettings.json is the default configuration store for ASP.NET Core applications. During development, engineers commonly place authentication settings directly into the file, including Entra ID application registration identifiers and client secrets. When the application is packaged and deployed, that same JSON file can end up served as a static asset from the web root, committed to source control, or stored in a cloud artifact repository without access controls.

If the file is reachable over HTTP—for example, at https://example.com/appsettings.json—anyone can read it. Bots that crawl the internet for sensitive files and JSON key patterns routinely fingerprint such exposures. The harvested TenantId, ClientId, and ClientSecret are then fed into an OAuth 2.0 client credentials flow.

The OAuth Client Credentials Grant: Programmatic Token Theft

The Microsoft identity platform's OAuth 2.0 client credentials flow is designed for service-to-service authentication where no user interaction occurs. An application presents its ClientId and ClientSecret directly to the token endpoint and receives an access token that represents the application, not a human user. That token is a bearer credential for all APIs the app registration is permissioned to call—most critically Microsoft Graph.

The attack flow is straightforward and fully documented by Microsoft:

  1. Attacker sends a POST request to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token with grant_type=client_credentials, client_id, client_secret, and scope=https://graph.microsoft.com/.default.
  2. The endpoint returns an access_token, typically valid for minutes to an hour.
  3. The attacker uses that bearer token to call any Graph API endpoint allowed by the application's permissions: GET /users, GET /groups, GET /directoryRoles, or administrative write endpoints if the app is overprovisioned.

Because the flow bypasses all user-centric controls—MFA, conditional access policies, interactive consent—a leaked client secret is functionally equivalent to handing an attacker a service account credential that cannot be stopped by any user-based security measure. Scripted token requests can maintain near-continuous access until the secret is rotated or revoked.

Blast Radius: Permissions Are Everything

The damage from a leaked client secret scales directly with the permissions assigned to the app registration. An application with minimal custom API scopes poses little risk. However, many applications are granted broad application-level permissions during development—Directory.Read.All, Application.ReadWrite.All, Mail.Read, and Sites.Read.All are common in enterprise app registries. Such overprovisioned apps turn a single leaked JSON file into a catastrophic event:

  • Directory.Read.All enables export of the entire directory, including user principal names, group memberships, and directory role assignments.
  • Mail.Read (if consented by an admin) permits reading mailboxes across the organization.
  • Application.ReadWrite.All allows creation of new app registrations and addition of credentials to existing service principals, a persistence mechanism that survives initial secret rotations.

Recent incident writeups show attackers enumerating directory objects, identifying privileged accounts, and then creating new app registrations with their own credentials to maintain long-term access.

The Attacker Playbook: From Harvest to Persistence

Defenders should understand the four-step sequence that threat actors execute after discovering an exposed appsettings.json:

  1. Harvest – Scan public web roots, GitHub commits, and object storage for appsettings.json. Extract TenantId, ClientId, ClientSecret. Automated bots perform this at internet scale in minutes.
  2. Token Exchange – Call the token endpoint using the harvested credentials to obtain an application-only access token. No MFA or consent prompt blocks this step.
  3. Enumeration – Query Microsoft Graph at scale. List users, groups, roles, subscriptions. If the app has mail or file permissions, exfiltrate content. Attackers often script thousands of API calls in a short window.
  4. Escalation and Persistence – If the compromised app has write privileges, or if other overprivileged apps are discovered during enumeration, create new app registrations, add additional credentials (client secrets or certificates) to service principals, or grant new permissions. This ensures access survives rotation of the initial compromised secret.

Each step is fully automatable. Token lifetimes limit a single token's usefulness, but requesting a new token is trivial. Attackers can loop the token request as long as the secret remains valid.

Real-World Outcomes

Independent reports describe consistent, alarming consequences: rapid directory enumeration, mailbox and SharePoint exfiltration where permissions allow, identification of administrative accounts, and attempts to plant backdoors by registering new applications. In at least one documented case, attackers used the initial reconnaissance to map out Global Admin roles and then targeted those accounts directly through other vectors. The exposure provided the initial foothold from which a much broader campaign launched.

Detection and Immediate Containment

Stopping an ongoing campaign requires recognizing the signals that application-only token abuse generates. The critical point: app-only activity does not appear in interactive sign-in logs the same way user logins do. Defenders must monitor non-interactive sign-ins and service principal activity streams.

Detection Signals to Prioritize

  • Non-interactive sign-ins – Look for grant_type=client_credentials events and sign-ins where the application is a service principal. These appear in Entra ID sign‑in logs under the "Non-interactive user sign-ins" or "Service principal sign-ins" tab.
  • Unfamiliar IP ranges or user agents – Attackers often originate from commodity cloud infrastructure (AWS, DigitalOcean, VPS providers). Geolocation anomalies or user agents like "python-requests" are strong indicators.
  • Sudden spikes in Graph API calls – Large, short bursts of GET /users, GET /groups, or GET /oauth2PermissionGrants indicate automated enumeration. Use Microsoft Graph activity logs or Azure Monitor to spot these surges.
  • Unexpected app registrations or credential modifications – Audit for newly created applications, added client secrets, or new certificate credentials on existing service principals.

0–72 Hour Containment Checklist

  1. Rotate compromised secrets immediately. Revoke the existing client secret from the app registration and generate a new one. Assume compromise even if no evidence of use exists—secrets in the wild are always dangerous.
  2. Disable the affected service principal. If the app is not critical to business operations, disable it entirely until investigation concludes.
  3. Remove exposed appsettings.json files. Scan web roots, object storage buckets, and public repositories. If found in a version control system, treat the entire commit history as compromised and rotate all associated credentials.
  4. Preserve logs and evidence. Export sign-in logs, Graph activity logs, and any relevant server logs covering the period before rotation. This data is essential for post-incident forensic analysis and indicator development.

These immediate actions are the minimum required to stop script-driven token re-requests and to prevent the secret from being used again.

Short- and Medium-Term Remediation

Short Term (72 hours – 30 days)

  • Adopt managed identities or certificate-based authentication for all Azure‑hosted applications. Managed identities eliminate client secrets from the equation entirely and are Microsoft's recommended path for service-to-service authentication.
  • Perform a full application permission audit. Enumerate all app registrations, service principals, and assigned application permissions. Remove or tighten any broad privileges (Application.ReadWrite.All, Directory.Read.All) that are not strictly required.
  • Harden CI/CD pipelines by adding automated secret scanning to block builds containing secrets. Tools like GitHub Advanced Security, Azure DevOps secret scanning, or pre-commit hooks prevent secrets from ever reaching artifacts.

Medium Term (30 – 90 days)

  • Centralize secret management in Azure Key Vault (or equivalent). Reference secrets in application configuration via Key Vault references, loaded at runtime using managed identities or certificate‑based authentication. Eliminate static secrets from configuration files entirely.
  • Enforce least privilege and admin consent controls. Require admin consent for all application‑level permissions. Implement app consent policies that restrict which types of permissions developers can request without review.
  • Automate SIEM detections. Add rules for unusual Graph API call patterns, large directory enumerations, and token acquisition from unexpected IP ranges. Tune these rules to reduce false positives while catching real attacks.

Engineering Practices That Prevent Future Leaks

  • Never store production secrets in appsettings.json or any file that could be checked in. Use environment‑specific configuration that references a secrets vault. Add appsettings.json to .gitignore and rely on user secrets for local development.
  • Prefer managed identities for all Azure resources. They remove the need to provision, store, or rotate client secrets in application code.
  • Use certificate‑based or federated credentials instead of long‑lived plaintext client secrets for high‑value applications. Certificates can be rotated and revoked more safely and offer stronger cryptographic guarantees.
  • Automate secret scanning everywhere—pre‑commit hooks, CI pipeline gates, artifact scanning, and runtime monitoring. GitHub secret scanning and pre‑build scanning in Azure DevOps should be enabled to catch leaks before they become public.
  • Limit requested permissions to the absolute minimum. Document the business need for each permission. Require admin approval for any application permission that grants broad access, and maintain an approval trail for audits.

Governance, Detection Limitations, and Residual Risks

Detection Challenges

Because application‑only tokens never involve a human user, traditional security controls like MFA and conditional access are irrelevant. Defenders cannot rely on interactive sign‑in anomalies alone; they must actively monitor service principal sign‑ins and Graph API usage. The sheer volume of legitimate background activity in large tenants can also mask malicious automation, requiring tailored baseline behaviors.

Token lifetimes mitigate the risk but do not solve it. Even with short-lived tokens (e.g., 30 minutes), an attacker can continuously request new tokens until the secret is revoked. Token lifetime is a delaying tactic, not a defense.

Organizational Friction

Development velocity often pressures teams to store secrets in configuration files. appsettings.json is familiar, pipelines are designed to promote artifacts, and legacy patterns persist. Changing this requires integrated platform tooling that removes friction: making managed identities the default, auto‑injecting vault references at deploy time, and educating developers on why the old pattern is dangerous.

Sticky Secrets

Once a secret appears in a public repository, container image, or web root, it can be cached by multiple actors—search engines, web archives, and malicious scanners. Rotation and revocation must be immediate and assumed to be incomplete if any copy may have been saved. A proactive scan of internet caches and code hosting platforms is a critical part of post-leak containment.

Residual Risks

Not all exposures are externally visible. A secret leaked into a private artifact store or a partner network can still be exploited without public evidence. The safest posture is to treat any committed secret as compromised, regardless of whether the leak seems public. Additionally, some remediation steps—like replacing certificate‑based credentials or integrating Key Vault—require careful change windows with rollback plans to avoid production outages.

Critical Analysis: Where Defenders Should Focus

Microsoft provides robust, integrated alternatives to plaintext client secrets: managed identities, Key Vault, and certificate/federated credentials. The technology exists; the gap is adoption. Combined with modern secret‑scanning tools in CI/CD pipelines, the platform gives defenders a strong baseline.

Yet the primary weak points remain developer patterns and overprovisioned permissions. The convenience of appsettings.json and the friction of setting up managed identities lead to repeated mistakes. Permissions granted during development are rarely revisited, leaving apps with broad access they never needed in production.

Defenders should prioritize, in this order:

  1. Immediate rotation and revocation of any exposed secrets; disable affected service principals until verified safe.
  2. Replacement of client‑secret‑based authentication with managed identities or certificate/federated credentials wherever possible.
  3. Full permission audit to downgrade application‑level privileges to the minimum.
  4. Pipeline hardening: block builds containing secrets, scan artifacts before release, and protect storage.
  5. SIEM rules focused on non‑interactive sign‑ins and Graph API anomalies, with automated alerting.

Practical Playbook for Azure Tenant Owners

  • Inventory – Use Azure CLI or Graph API to list all app registrations, their credential types (secrets/certificates), assigned application permissions, and associated service principals.
  • Search – Scan public web roots, storage buckets, container registries, and source code repositories for appsettings.json files containing AzureAd keys. Tools like git-secrets, truffleHog, and Azure DevOps secret scanning can assist. Treat any match as a confirmed leak.
  • Rotate – For each exposed secret, remove it from the app registration and generate a new one. If rotation breaks production, stage a rollout to certificate‑based auth or managed identity first.
  • Quarantine – Disable the compromised service principal or restrict its permissions while you validate the environment and review logs.
  • Investigate – Export non‑interactive sign‑in logs and Graph activity logs for the exposure window. Look for suspicious token requests, unfamiliar IPs, and unusual API call patterns. Preserve all forensic evidence.
  • Harden – Deploy Key Vault, enable managed identities, enforce admin consent for application permissions, and apply automated secret scanning across all CI/CD stages.

What’s Verified and Where Caution Is Needed

Multiple independent publisher and researcher reports confirm the core technical facts: exposed appsettings.json files containing ClientId and ClientSecret allow attackers to perform the OAuth 2.0 client credentials flow and call Microsoft Graph as the application. This is consistent with Microsoft’s own documentation on client secret management and application permissions.

However, specifics such as the exact number of affected tenants, the identities of impacted organizations, or whether privilege escalation to Global Admin occurred in every case remain unverified in public records. When public data is sparse, the only safe stance is to assume compromise and act conservatively: rotate, revoke, and inspect.

The threat is real, automatable, and trivially exploitable. The difference between a harmless configuration file and a tenant-wide breach is often a single misplaced secret—and closing that gap must be an immediate, measurable priority.