Skip to content
Back to skills

Dotnet Dynamic Configuration

ASecurity

Reviews where ASP.NET Core configuration values live. Flags business-tunable settings hardcoded in appsettings.json instead of a DB-backed configuration source, secrets stored in the DB config table instead of Key Vault, undocumented precedence between bootstrap appsettings.json and DB-backed values, DB config read on every request with no caching/invalidation, and no admin surface to edit DB config. Outputs findings with pilot-dotnet dynamic-configuration standard IDs.

  • 2 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 6, 2026
developmentgosqlazureapidatabase

Works with

  • api

Security analysis

A100/100

Scanned September 6, 2026

npx -y skills add AgenticPawan/FullStack-Pilot --skill dotnet-dynamic-configuration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dotnet Dynamic Configuration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dotnet Dynamic Configuration
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/agenticpawan-dotnet-dynamic-configuration/badge)](https://www.skillsdirectory.com/skills/agenticpawan-dotnet-dynamic-configuration)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dotnet-dynamic-configuration
description: Reviews where ASP.NET Core configuration values live. Flags business-tunable settings hardcoded in appsettings.json instead of a DB-backed configuration source, secrets stored in the DB config table instead of Key Vault, undocumented precedence between bootstrap appsettings.json and DB-backed values, DB config read on every request with no caching/invalidation, and no admin surface to edit DB config. Outputs findings with pilot-dotnet dynamic-configuration standard IDs.
when_to_use: IConfigurationSource, DB-backed configuration, dynamic configuration, feature flag, appsettings.json, Key Vault secret, App Insights instrumentation key, configuration precedence, configuration caching, IOptionsMonitor, runtime configuration change, admin settings
---

## Standard IDs

| ID | Severity | What it checks |
|----|----------|-----------------|
| CFG-001 | P1 | Business-tunable setting hardcoded in `appsettings.json` instead of DB-backed |
| CFG-002 | P0 | Secret stored in the DB config table instead of Key Vault |
| CFG-003 | P2 | No documented/enforced precedence between bootstrap config and DB-backed config |
| CFG-004 | P2 | DB-backed config read per-request with no caching/invalidation |
| CFG-005 | P3 | No admin surface to edit DB config values (advisory) |

---

## Check A — Business-tunable setting hardcoded in appsettings.json (CFG-001)

### Detection

1. Grep `appsettings*.json` for values that are business/ops-tunable (feature flags, retry thresholds, email-template subjects, job cron/enabled flags — see `dotnet-background-jobs` BGJ-002) rather than deployment-topology values (connection strings, service URLs).
2. If changing one of these values requires a redeploy instead of an admin-panel edit or DB update, flag it.
3. Deployment-topology values (DB connection string, Key Vault URI, App Insights instrumentation key) are explicitly **not** a finding here — see Check B for why those must stay out of the DB.

### BAD — feature flags and thresholds baked into appsettings.json

```json
{
  "Features": { "NewCheckoutFlow": false },
  "Orders": { "MaxRetryAttempts": 3, "LowStockThreshold": 10 }
}
```

### GOOD — a DB-backed configuration source layered over appsettings.json

```csharp
public class DatabaseConfigurationSource : IConfigurationSource
{
    public IConfigurationProvider Build(IConfigurationBuilder builder) => new DatabaseConfigurationProvider();
}

public class DatabaseConfigurationProvider : ConfigurationProvider
{
    public override void Load()
    {
        using var scope = ServiceProviderAccessor.Root.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        Data = db.AppSettings.ToDictionary(s => s.Key, s => s.Value); // "Features:NewCheckoutFlow" -> "true"
    }
}

// Program.cs
builder.Configuration.AddDatabaseConfiguration(); // added AFTER appsettings.json so DB values win — see Check C
```

---

## Check B — Secret stored in DB config table (CFG-002)

### Detection

1. Grep the DB-backed settings table's seeded/inserted values (and any admin endpoint that writes to it) for connection strings, API keys, JWT signing keys, or third-party credentials.
2. Secrets must come from Key Vault (or another dedicated secret store) — the DB config table is for non-secret, business-tunable values only. A secret sitting in an ordinary settings table is readable by anyone with DB read access or a SQL-injection foothold, with no audit trail or rotation support.

### BAD — API key stored alongside feature flags in the settings table

```csharp
await _db.AppSettings.AddAsync(new AppSetting { Key = "Payments:StripeApiKey", Value = "sk_live_..." });
```

### GOOD — secret stays in Key Vault, only its *reference* (if anything) touches app config

```csharp
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
// "Payments:StripeApiKey" resolves from Key Vault, never from the AppSettings DB table.
```

---

## Check C — No documented precedence between bootstrap and DB config (CFG-003)

### Detection

Check whether `Program.cs` clearly establishes and documents (comment or naming) that `appsettings.json`/environment variables/Key Vault are for *bootstrap-only* values (the connection string that reaches the DB in the first place, the Key Vault URI, the App Insights key) and are loaded before the DB-backed provider, with DB values taking precedence for everything else. Flag ambiguous ordering where it's unclear which source wins for a given key.

### BAD — DB config source added with no stated precedence

```csharp
builder.Configuration.AddDatabaseConfiguration();
builder.Configuration.AddJsonFile("appsettings.json"); // added after — silently overrides DB values, defeats the purpose
```

### GOOD — explicit precedence, bootstrap-only keys called out

```csharp
// 1. appsettings.json / env vars: BOOTSTRAP ONLY — DB connection string, Key Vault URI, AI instrumentation key
builder.Configuration.AddJsonFile("appsettings.json").AddEnvironmentVariables();

// 2. Key Vault: secrets (never stored in the DB config table — see Check B)
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());

// 3. DB-backed config: everything else, added LAST so it overrides bootstrap defaults
builder.Configuration.AddDatabaseConfiguration();
```

---

## Check D — DB config read per-request with no caching (CFG-004)

### Detection

Check whether `IConfiguration`/`IOptionsMonitor<T>` backed by the DB provider re-queries the database on every access, or whether the provider caches loaded values in memory with a change-token/polling refresh (`ConfigurationProvider.OnReload()` on a timer, or a cache invalidated by the admin-edit endpoint).

### BAD — every config read hits the database

```csharp
public string GetFeatureFlag(string key) =>
    _db.AppSettings.Single(s => s.Key == key).Value; // one query per call, every request
```

### GOOD — cached with a refresh trigger

```csharp
public class DatabaseConfigurationProvider : ConfigurationProvider
{
    public override void Load() => ReloadFromDatabase(); // called once at startup...

    public void TriggerReload() // ...and again whenever the admin endpoint saves a change
    {
        ReloadFromDatabase();
        OnReload();
    }
}
```

---

## Check E — No admin surface to edit DB config (CFG-005, advisory)

### Detection

Confirm there is an authorized admin endpoint/UI (permission-gated, per `dotnet-authorization`) to add/update/remove DB-backed settings, rather than requiring a direct database edit for every change — otherwise the "no redeploy needed" benefit from Check A is only half-realized.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.