A single, publicly exposed appsettings.json file containing Azure Active Directory (now Entra ID) application credentials can act as a master key to an organization’s entire cloud estate, security researchers have confirmed. The misconfiguration – a forgotten configuration file sitting on a web server or in a public repository – hands attackers a ClientId and ClientSecret that can be silently exchanged for OAuth 2.0 access tokens, bypassing all user-facing multi-factor authentication. The threat is not theoretical: Resecurity’s HUNTER team documented active exploitation scenarios where such leaks enabled automated harvesting of Microsoft Graph data at scale, mapping users, groups, and administrative roles in minutes.
This class of breach is a direct consequence of developer convenience colliding with production security. appsettings.json, the standard configuration file for ASP.NET Core applications, often holds sensitive keys during development. When deployment pipelines push the same file into production – or when a misconfigured web server serves it as a static asset – the entire authentication infrastructure of an application becomes trivially accessible to anyone scanning for common JSON filenames.
How the Exposure Happens – Predictable Patterns, Recurring Failures
The root cause is human and pipeline error, not a flaw in Microsoft’s identity platform. Developers store AzureAd:ClientId and AzureAd:ClientSecret in appsettings.json because it works perfectly in local testing. The file uses a clear, hierarchical JSON structure, making secrets easy to find with automated crawlers. Three common pathways turn a local convenience into a production catastrophe:
- Deployment automation promotes entire configuration folders without stripping secrets. Infrastructure-as-code and CI/CD scripts often treat appsettings.json as just another artifact to copy.
- Web root misconfigurations place the file inside
wwwrootor an equivalent publicly accessible directory. A build step that copies configuration for internal use can accidentally expose it if the web server’s file-serving rules are too permissive. - Source control leaks – committing appsettings.json to a public GitHub repository, or even a private one that later becomes public, is a well-known antipattern. Bots constantly scrape repositories for strings matching common key patterns like
"ClientSecret".
These vectors are so well documented that platforms like Microsoft Learn and community sites such as Code Maze and C# Corner repeatedly warn against them. Yet time pressure, legacy habits, and the sheer simplicity of the approach keep the problem alive. As one researcher noted, the same configuration schema travels across environments, so a single slip exposes production credentials.
The Attack Mechanics – From JSON to Tenant Takeover
When an attacker locates a live appsettings.json, the extraction is immediate: the file is human-readable and the keys are self-documenting. The attacker retrieves the TenantId, ClientId, and ClientSecret. With those three pieces, they can execute an OAuth 2.0 client credentials grant – a machine-to-machine flow that requires no user interaction and no MFA prompt.
Step 1: Token Acquisition
A single POST to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token with grant_type=client_credentials, the leaked client_id and client_secret, and scope=https://graph.microsoft.com/.default returns a bearer access token. Because the credentials belong to an application, the identity platform sees a legitimate app requesting its own token. No user anomaly is triggered.
Step 2: Graph Enumeration
The token’s power is defined by the application permissions (app roles) assigned to the service principal. If an administrator granted broad scopes – Directory.Read.All, User.Read.All, Group.Read.All, or worse, Application.ReadWrite.All – the attacker can list every user, group, administrative role, and service principal in the tenant. A single call to GET /users dumps the directory; GET /oauth2PermissionGrants reveals which apps have been consented and with what scopes.
Resecurity’s HUNTER team demonstrated that an app with sufficient privileges can pivot from enumeration to data exfiltration. An Application.ReadWrite.All scope, for example, allows creation of new app registrations or addition of credentials to existing service principals, establishing persistence that survives initial credential rotation.
Step 3: Lateral Movement and Persistence
Once the attacker maps the tenant, they identify high-value targets: Global Administrators, users with mailbox access, owners of sensitive service principals. They can read mailboxes (Mail.Read), download SharePoint files (Sites.Read.All), or call Azure Resource Manager APIs if the app had management plane permissions. Critically, they can create new applications with malicious consent grants or add their own credentials to an existing highly-privileged app – a technique that allows long-term, silent access even after the original secret is rotated.
Token Lifetime Constraints
Access tokens obtained via client credentials have a default lifetime of roughly 60–90 minutes and do not come with refresh tokens. However, the attacker can simply re-request a new token using the same leaked secret as long as that secret is valid. This means the window for abuse is open until the secret is explicitly revoked or rotated. Automated scripts cycle through token requests seamlessly, turning a brief exposure into a multi-hour campaign.
Real-World Impact – What the Reports Show
The Resecurity HUNTER team’s investigation confirmed multiple tenants where publicly reachable appsettings.json files were harvested and used to obtain app-only tokens. In at least one observed case, attackers enumerated administrative roles and pinpointed privileged resources that could be targeted for escalation. The activity matches established playbooks: fully automated pipelines that scan for configuration files, extract credentials, and immediately begin directory traversal.
Independent reports across darkreading.com and other security outlets highlight the speed at which this escalates. A single exposed file can be discovered within hours of publication because crawlers prioritize common paths like /appsettings.json and /appsettings.Development.json. The blast radius is entirely dependent on the permissions the compromised application possessed. An app with only limited, custom API scopes might reveal little; an app granted Directory.ReadAll or Application.ReadWrite.All provides the skeleton keys for a tenant-wide breach.
Extrapolated worst-case outcomes – full mailbox exfiltration, complete tenant takeover – are possible if the app held sufficiently broad permissions. However, researchers caution that the exact impact varies. Unverified claims of total compromise should be weighed against the actual permission assignments, which can be confirmed via Graph audit logs.
Detection and Triage – How to Know if You Were Hit
Immediate incident response revolves around log analysis and credential hygiene. Organizations should prioritize these steps:
- Audit web-facing assets and repositories for any appsettings.json files containing keys. Tools like GitHub secret scanning or simple curl tests against known endpoints can surface exposures quickly.
- Analyze non-interactive sign-in logs in the Entra admin center (or Azure AD portal) for the client ID associated with the exposed app. Look for token requests originating from unfamiliar IP addresses or user agents. Since client credential flows are non-interactive, they appear as “application” sign-ins.
- Review Microsoft Graph activity logs for unusual enumeration patterns – large numbers of
/usersor/groupscalls, or queries to/oauth2PermissionGrantsand/applicationsthat are atypical for the workload. - Inspect service principal credential changes. Any addition of new secrets or certificates after the exposure window is a red flag for persistence.
- Assume compromise until proven otherwise. Tokens can be used without obvious traces, so immediate rotation of all credentials associated with the affected service principal is mandatory.
Remediation Checklist – Immediate, Short-Term, and Medium-Term
Immediate (0–72 hours)
- Revoke and rotate exposed secrets. Delete the compromised client secret from the app registration in Entra ID. Generate a new secret or, ideally, switch to certificate-based credentials or federated identity credentials.
- Disable the compromised service principal if possible, until the investigation is complete. This halts all token issuance for that identity.
- Delete exposed appsettings.json files from public directories and repositories. If the file was in a repository, consider the commit history compromised; rotate secrets regardless of observed activity.
- Collect and preserve logs – export sign-in logs, Graph activity logs, and any relevant Azure resource logs for the period before rotation. This evidence is crucial for scope assessment.
Short-Term (72 hours – 30 days)
- Migrate to managed identities or certificate authentication. For Azure-hosted workloads, managed identities eliminate the need for client secrets entirely and completely prevent this leak vector.
- Perform a full application permission audit. Identify every service principal with high-privilege application permissions (
Directory.Read.All,Application.ReadWrite.All,RoleManagement.ReadWrite.Directory, etc.) and reduce them to the minimum necessary. Remove unused apps. - Harden CI/CD pipelines. Integrate secret scanning tools (e.g., Microsoft Credential Scanner, GitGuardian) that fail builds when patterns like
"ClientSecret"appear. Restrict artifact storage to authenticated users only.
Medium-Term (30–90 days)
- Centralize secret management with Azure Key Vault. Use RBAC and audit logging to control access. Modern ASP.NET Core apps can use
DefaultAzureCredentialand theAzure.Extensions.AspNetCore.Configuration.Secretspackage to retrieve secrets at runtime, decoupling them from files. - Enforce least privilege and consent policies. Require administrator approval for all application permissions, and deploy app consent policies that limit what apps end users can consent to. Enable continuous access evaluation controls where possible.
- Automate detection of suspicious app behavior. Tune SIEM rules to alert on unusual Graph call volumes, token requests from unexpected geolocations, or user agents associated with known OAuth abuse toolkits.
Developer Best Practices – Preventing the Next Leak
Prevention must be architectural, not procedural. The following practices turn this predictable failure into an avoidable one:
- Never store production secrets in appsettings.json. Use environment-specific configuration providers: user secrets during local development (with
dotnet user-secrets), environment variables in staging, and Key Vault or managed identity references in production. - Leverage Azure Key Vault and managed identities. For services running in Azure, enable a system-assigned managed identity and grant it read access to a Key Vault. The Azure SDK’s
SecretClientretrieves values without any hardcoded credentials. - Prefer certificate credentials or federated identity credentials over client secrets. Certificates are harder to accidentally leak and can be stored in Key Vault. Federated identities for GitHub Actions or Kubernetes eliminate secrets altogether.
- Apply least privilege from day one. Only request application permissions that are strictly required. If your app only needs to read user profiles, request
User.Read.Alland neverDirectory.Read.All. Review the Microsoft Graph permissions list to identify high-risk scopes. - Add appsettings.json to .gitignore and enforce it via repository-level rules. Configure branch protection to reject commits that contain secret patterns.
Strengths, Weaknesses, and Systemic Risks
What works:
Microsoft provides a mature, well-documented suite of defenses: managed identities, Key Vault integration, certificate credentials, and granular application permission scopes. Combined with Entra ID’s rich sign-in and audit logs, organizations have the tools to detect and prevent this threat at scale.
Why it persists:
The core issue is not technology but operational discipline. The developer experience of dropping secrets into a JSON file is frictionless, and automation often amplifies mistakes. Many teams lack the DevSecOps maturity to shift secret management left. The power of application permissions also amplifies the problem: a single over-permissioned app can turn a minor leak into a catastrophe because application tokens bypass user MFA and can be used for high-speed, unattended data access.
Systemic risk:
As cloud adoption accelerates, the surface area of misconfigured files grows. The pattern is predictable and will continue until organizations treat application identity with the same rigor as user identity. The gap between “works on my machine” and “deployed securely” remains a consistent failure point. Industry reports indicate that opportunistic scanning is not declining, and the financial impact of a breach that moves from a JSON file to full directory control can be enormous.
A Note on Unverified Claims
Some public write-ups, including those cited in the Resecurity report, extrapolate worst-case scenarios such as mass mailbox exfiltration or instant tenant takeover. While these outcomes are possible if the compromised app had the necessary permissions, they are not automatic. The real impact depends entirely on the granted scopes. During an investigation, always confirm the app’s permission assignments via the Entra admin center or Graph Explorer before assuming a full compromise. Similarly, while automated bots harvest secrets aggressively, determining whether a particular secret was used in a live compromise requires forensic log analysis. Absence of immediate evidence does not mean a breach did not occur.
The Bottom Line for Windows Admins and Architects
A single exposed appsettings.json file is not a zero-day vulnerability – it is an operational failure that creates a zero-effort attack path. The discovery by Resecurity’s HUNTER team underscores how trivial it is for attackers to weaponize a forgotten configuration snippet. The defensive path, however, is clear: eliminate secrets from files, lock down application permissions, and automate detection.
For Windows administrators and Azure architects, the actionable priorities are:
- Scan all internet-facing assets and repositories for exposed appsettings.json files today.
- Migrate every production workload to managed identities or Key Vault-backed secrets.
- Audit all app registrations and prune permissions to the absolute minimum.
- Harden CI/CD pipelines so no build artifact ever contains a plaintext secret.
The technical guidance exists across Microsoft Learn and security community resources. The only remaining variable is whether organizations apply it before the next automated scanner finds an exposed file. In the cloud era, security is not about one big fix; it’s about closing the operational gaps that turn a harmless JSON file into a master key.