Secrets config audit
Skill tunahanaliozturk/secure-dotnet-skills/skills/secrets-config-audit
Use when auditing a .NET app for secret handling and configuration safety — hardcoded secrets, secrets in source or appsettings, Azure Key Vault wiring, and managed-identity usage.From its SKILL.md
npx -y skills add tunahanaliozturk/secure-dotnet-skills --skill secrets-config-auditAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.3 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Secrets & Config Audit
Directs the agent to audit a .NET / ASP.NET Core application for secret-handling failures and configuration-provider gaps, producing a concrete remediation path for each finding — naming the Key Vault API, DefaultAzureCredential pattern, or config-layer fix required.
When to use
- Any PR or codebase audit where connection strings, API keys, client secrets, SAS tokens, or passwords may appear in source or
appsettings*.json. - Before onboarding an app to Azure: confirming Key Vault is wired, managed identity is used, and no raw secrets travel through environment variables or app settings.
- Post-incident: validating that a leaked secret has been rotated and the root cause (wrong config layer) is fixed.
- Pre-deploy security gate for any .NET service that calls Azure Storage, Azure SQL, Cognitive Services, or third-party APIs.
Process
- Scan source and
appsettings*.jsonfor literal secrets. Search forPassword=,ClientSecret,AccountKey,SharedAccessSignature,apiKey, bearer token literals, and connection-string patterns. Flag every occurrence, includingappsettings.Development.json— development files are committed and leak via git history. - Map the configuration layering and decide where each secret belongs. Trace the config provider registration order in
Program.cs(appsettings.json→appsettings.{Environment}.json→ environment variables → user-secrets → Key Vault). Assign each secret to its correct layer: non-sensitive defaults inappsettings.json, development-only values indotnet user-secrets, production secrets exclusively in Key Vault. - Verify Key Vault integration and its authentication. Confirm
AddAzureKeyVault(new Uri(vaultUri), new DefaultAzureCredential())is registered inProgram.cs, thatKeyVault:VaultUri(or equivalent) is the only Key Vault-related value inappsettings.json, and that noClientId/ClientSecretpair is stored in config to authenticate to Key Vault itself — that is the managed-identity anti-pattern. - Confirm logging and exception paths never emit secrets. Review every
ILoggercall, exception handler, andIOptions<T>binding near sensitive config sections. ALogInformationcall that dumps anIOptions<DatabaseOptions>instance, or a caught exception that formats a connection string, silently exfiltrates secrets to the log sink. - Give a remediation path per finding. Each finding must name the specific config value to remove, the Key Vault secret name to create (observing the
:→--naming rule), the RBAC role to grant, and the code change required inProgram.cs. "Move to Key Vault" is not a remediation; the exact secret name, vault URI source, andAddAzureKeyVaultwiring are.
.NET / Azure checks
- Literal secrets in source or committed config. Flag any
"Password=…","ClientSecret","AccountKey","SharedAccessSignature", or API key value inappsettings*.json,*.jsonresource files,web.config,.envfiles, or C# string literals. Evenappsettings.Development.jsonis committed; secrets there are in git history permanently after removal. - Config provider order and secret layer assignment. In
Program.cs, confirm the host builder registers providers in the correct order:appsettings.json(non-sensitive defaults) →appsettings.{env}.json(env-specific non-sensitive) → environment variables →builder.Configuration.AddUserSecrets<Program>()(dev only; never in production) →AddAzureKeyVault(...)(production secrets). Secrets surfacing from the wrong layer (e.g., a production password in an environment variable on App Service instead of Key Vault) are a misconfiguration finding. AddAzureKeyVaultwiring withDefaultAzureCredential. ConfirmProgram.cscallsbuilder.Configuration.AddAzureKeyVault(new Uri(builder.Configuration["KeyVault:VaultUri"]!), new DefaultAzureCredential()). The vault URI must itself come from a non-secret config value (it is not a secret). PreferDefaultAzureCredentialoverClientSecretCredential— anyClientSecretCredentialthat takes a secret from config is an anti-pattern: the secret that authenticates to Key Vault must not live in config.- Managed identity vs client secret for Azure service authentication. Flag any
ClientId+ClientSecretpair in config used to authenticate to Azure services (Key Vault, Storage, Service Bus, SQL). The correct pattern for App Service / Container Apps / AKS is a system-assigned or user-assigned managed identity withDefaultAzureCredential; no credential material touches config or code. For local development,DefaultAzureCredentialfalls through toVisualStudioCredential/AzureCliCredential— no secret required there either. - Key Vault secret naming for nested config (
:→--). Azure Key Vault does not allow:in secret names. The Key Vault configuration provider maps--to:at read time, soConnectionStrings:DefaultConnectionmust be stored as the Key Vault secretConnectionStrings--DefaultConnection, andAzureAd:ClientSecretasAzureAd--ClientSecret. Verify that the secret names in Key Vault match the config keys the app reads; a mismatch silently falls back to the lower-priority provider (which may still hold a stale literal). - RBAC vs legacy access policies on Key Vault. Key Vault supports two authorization models: the modern Azure RBAC model (grant
Key Vault Secrets Userto read secrets,Key Vault Secrets Officerto create/update) and the legacy access-policy model. Flag any vault configured with access policies — the RBAC model is auditable via Azure Policy, scoped to individual secrets, and aligns with the principle of least privilege.Key Vault Secrets Useris sufficient for app reads;Key Vault Secrets Officeris required for deployment pipelines that write secrets. FlagKey Vault ContributororOwneron an app identity — these are resource-plane roles, not data-plane roles, and do not grant secret reads but do grant the ability to reconfigure the vault. - Storage: SAS/account keys vs RBAC. Flag any Azure Storage
AccountKeyor SAS token in config. The correct pattern isDefaultAzureCredential+BlobServiceClient(new Uri(...), new DefaultAzureCredential())with the managed identity holdingStorage Blob Data ContributororStorage Blob Data Reader. Account keys bypass Azure RBAC entirely and grant full storage-account access if leaked. IOptions<T>binding and secret redaction in logs. WhenIOptions<DatabaseOptions>or similar binds a config section that contains a password or key, confirm that the type does not implementToString()in a way that dumps field values, and that noLogDebugorLogInformationcall passes the options object (or its properties) as a structured parameter._logger.LogInformation("Connecting with {@opts}", _options.Value)serializes the entire object — includingPassword— into the structured log sink.
Red flags
| Signal | Why it matters |
|---|---|
"Password=s3cr3t;" in appsettings.json or appsettings.Development.json | Committed to git history permanently; rotation is necessary but does not remove the historical exposure. Rotate immediately and move to Key Vault. |
"ClientSecret": "abc123..." in any appsettings*.json | An Entra ID / OAuth client secret in config is a credential leak — any developer with repo access or any log aggregator that captures config can impersonate the app's service principal. |
Server=…;User Id=…;Password=… connection string literal in source or config | Full database credentials exposed; if the connection string appears in logs (e.g., via a caught SqlException), the password is in the log sink. Move to managed identity + Authentication=Active Directory Managed Identity in the connection string. |
new ClientSecretCredential(tenantId, clientId, config["AzureAd:ClientSecret"]) in Program.cs | Using a secret to authenticate to Azure — this defeats the purpose of Key Vault if the secret is in config, and defeats managed identity. Switch to DefaultAzureCredential. |
Key Vault secret named ConnectionStrings:DefaultConnection (with :) | Colons are invalid in Key Vault secret names; the provider never resolves this secret, so the app silently falls back to a lower-priority provider (possibly a committed literal). Rename to ConnectionStrings--DefaultConnection. |
Key Vault access policy grants instead of RBAC roles (Key Vault Secrets User) | Access policies are coarser-grained than RBAC, cannot be scoped below the vault level, and are not auditable via Azure Policy. Migrate to the RBAC authorization model. |
AccountKey or SharedAccessSignature in App Service app settings | App settings are visible in the Azure Portal to anyone with Contributor on the App Service resource, and may appear in deployment logs. Replace with managed identity + BlobServiceClient(..., new DefaultAzureCredential()). |
builder.Configuration.AddUserSecrets<Program>() called without if (builder.Environment.IsDevelopment()) guard | User secrets are a dev-only mechanism; calling them unconditionally means they are active in production where the secrets file may be present on the host, bypassing Key Vault. |
_logger.LogInformation($"Connecting: {connectionString}") | Interpolated log line bakes the full connection string (with password) into the log message. Structural log sinks serialize it as a raw string; redaction is impossible after the fact. |
Key Vault Contributor role assigned to a managed identity | Contributor is a resource-plane role — it controls vault configuration, not secret reads — but it enables reconfiguring the vault's access model, making it a privilege-escalation vector. |
Example
See examples/secrets-config-audit/.
Related skills
- dotnet-security-review — use for a full security review beyond secret handling (injection, crypto, deserialization).
- azure-hardening-review — use to review Key Vault configuration, RBAC roles, and managed identity posture in Azure infrastructure.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.