Install
$ agentstack add skill-tunahanaliozturk-secure-dotnet-skills-secrets-config-audit ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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, andIOptionsbinding near sensitive config sections. ALogInformationcall that dumps anIOptionsinstance, 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()(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. IOptionsbinding and secret redaction in logs. WhenIOptionsor 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() 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/](../../examples/secrets-config-audit/).
Related skills
- [dotnet-security-review](../dotnet-security-review/SKILL.md) — use for a full security review beyond secret handling (injection, crypto, deserialization).
- [azure-hardening-review](../azure-hardening-review/SKILL.md) — use to review Key Vault configuration, RBAC roles, and managed identity posture in Azure infrastructure.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: tunahanaliozturk
- Source: tunahanaliozturk/secure-dotnet-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.