appsettings.json Secrets Committed to Git
A real connection string, API key, or signing secret ended up in appsettings.json — not appsettings.Development.json — and got pushed. Deleting the line in a new commit removes it from the file. It does not remove it from history, and anyone who already cloned, forked, or has GitHub's cache of that commit still has it.
// first: rotate it, before anything else
// checking whether it's actually in history, not just the current file
// removing it from history
git filter-branch)filter-branch, which it describes as slow and easy to get wrong. Rewrites every commit that touched the file.git pull will merge the old history right back in.// structuring config so this can't happen again
The reliable fix isn't remembering to be careful — it's making the real secret physically unable to live in a file git tracks.
dotnet user-secrets init, then dotnet user-secrets set "ConnectionStrings:Default" "…" — stored outside the project folder entirely, on a path the ASP.NET Core configuration system reads automatically in Development, never on disk inside the repo.GitHub's push protection and secret scanning catch a lot of common key formats automatically on public repos (and on private repos with the feature enabled) and will block a push outright — useful as a backstop, but the config structure above is what prevents the situation rather than catching it after the fact. The appsettings.json Validator flags plaintext-looking secrets in a pasted file for the same reason: catching it before git commit is a lot cheaper than catching it after git push.
// frequently asked questions
What should I do first if a secret was committed to git?
Rotate it, before anything else. If a real secret was pushed to a remote — even briefly, even to a private repo, even if deleted thirty seconds later — treat it as compromised. GitHub caches commit contents independently of the repo, and any fork or clone made in that window keeps its own copy regardless of what happens to the history afterward. Everything else is worth doing, but none of it is a substitute for rotating the credential.
Does deleting the line from appsettings.json remove it from git history?
No. Deleting the line in a new commit removes it from the current file, not from history — anyone who already cloned, forked, or has GitHub's cache of that earlier commit still has it. History rewriting is a separate step from editing the file.
How do I check if a secret is actually in git history?
git log -p -- appsettings.json shows every version of the file across every commit, including ones a later commit "removed." If the secret shows up anywhere in that output, it's in history, and every clone of the repo has it.
What's the right way to remove a secret from git history?
Use git-filter-repo or BFG Repo-Cleaner, not git filter-branch (Git's own documentation describes it as slow and easy to get wrong). Either tool rewrites commit hashes for everything after the exposed commit, so every collaborator needs to re-clone or hard-reset afterward — a normal git pull will just merge the old history back in.
Where should secrets actually be stored instead of appsettings.json?
Locally, dotnet user-secrets init then dotnet user-secrets set stores values outside the project folder entirely, on a path ASP.NET Core reads automatically in Development. In production, use environment variables or a managed secret store (Azure Key Vault, AWS Secrets Manager), injected at deploy time. appsettings.json itself should only hold structure and non-secret defaults.
git log -p -- appsettings.jsonshows every version of the file across every commit — including ones a later commit "removed." If the secret shows up anywhere in that output, it's in history, and every clone of the repo has it.