Keeping credentials out of source, and what to do once one is in: rotate before removing, because deleting the line does not un-leak it. Covers where a secret may live, safe .env templates, why a client-reachable config value is public, and running a scanner rather than eyeballing for patterns. Use when writing code that reads a credential, creating config or .env templates, before committing, or after discovering a secret in a repository.
Install to Claude Code
npx -y skills add ShieldNet-360/secure-vibe --skill secret-detection --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Secret Detection?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/shieldnet-360-secret-detection-secure-vibe)More formats (shields.io, HTML) on the badges page.
---
name: secret-detection
description: "Keeping credentials out of source, and what to do once one is in: rotate before removing, because deleting the line does not un-leak it. Covers where a secret may live, safe .env templates, why a client-reachable config value is public, and running a scanner rather than eyeballing for patterns. Use when writing code that reads a credential, creating config or .env templates, before committing, or after discovering a secret in a repository."
---
<!-- Native skill bundle for Claude Code. Generated by `secure-vibe dev regenerate`. -->
<!-- Do not edit by hand; the source of truth is skills/secret-detection/SKILL.md. -->
# Secret Detection
Keeping credentials out of source, and what to do once one is in: rotate before removing, because deleting the line does not un-leak it. Covers where a secret may live, safe .env templates, why a client-reachable config value is public, and running a scanner rather than eyeballing for patterns. Use when writing code that reads a credential, creating config or .env templates, before committing, or after discovering a secret in a repository.
## ALWAYS
- On finding a committed credential, **rotate or revoke it at the provider first**. Deleting the line does not remediate it, and neither does `git rm`, an amended commit, or a history rewrite: the value reached a remote, a clone, a fork, a CI log and a backup, and it is compromised from the moment it was pushed. Rotate, then clean the history, then add the guard that stops it recurring — in that order, because only the first one is time-critical.
- **Run a scanner**; do not scan by eye. `scan_secrets` and `check_secret_pattern` carry the full pattern set with per-pattern entropy floors and hotword proximity, and a person reading a diff matches none of that reliably. A working-tree scan and a history scan answer different questions — the first says what you are about to commit, the second says what is already public.
- Read the credential from the environment or a secret manager at the point of use — `os.environ`, `process.env`, `os.Getenv`, a Vault / AWS Secrets Manager / GCP Secret Manager / 1Password client. Nothing about the value should be reconstructible from the repository.
- Ship a **`.env.example`** that is committed and contains every key with an empty or obviously-fake value, alongside a `.env` that is ignored and never committed. The example file is documentation, so it must never be produced by copying a working `.env` and editing it — that is how a real value survives into the template.
- Ignore the file classes that carry key material, in one list: `.env`, `.env.*` (but not `.env.example`), `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.ppk`, `id_rsa*`, `id_dsa*`, `id_ecdsa*`, `id_ed25519*`, `*credentials*`, `*secret*`. A `.gitignore` entry is a guard against habit, not a control — it does nothing for a file already tracked, and `git add -f` overrides it.
- Treat every **client-reachable config value as public**: a shipped bundle, a `/config` endpoint, Firebase Remote Config, a feature-flag payload, a mobile app's build-time constants. A client may hold public identifiers and nothing else.
- Prefer credentials that expire and are scoped. A short-lived, narrowly-scoped token bounds what a leak costs, and it is the only control that still helps after every other one has failed — which, given the rule above about rotation, is the case worth designing for.
## NEVER
- Hardcode an API key, token, password, connection string, or private key in source, and do not hide one in a default parameter, a test constant, a Dockerfile `ARG`, or a committed CI variable.
- Put a real secret in a **test fixture**. Use the documented placeholders — `AKIAIOSFODNN7EXAMPLE`, `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`, `xoxb-EXAMPLE-EXAMPLE` — which every scanner already excludes by name.
- Distribute a bearer secret to clients at **runtime** through a config or feature-flag service. Anyone holding the app's public configuration can fetch it, so it is exactly as exposed as a hardcoded one. Proxy the privileged call through an authenticated backend instead.
- Write a credential into a place designed to be read later: a log line, an error payload, a commit message, a PR or issue body, a CI job name, a screenshot in a ticket. `logging-security` owns the log sink; the others have no redactor at all.
- Treat a **pre-commit hook** as the control. `--no-verify` skips it, `git clone` does not carry it, and it never runs on the server or on a force-push. It is a convenience that catches accidents; the blocking CI check is the control, and `cicd-security` owns that gate.
## KNOWN FALSE POSITIVES
- The documented AWS example pair, `AKIAIOSFODNN7EXAMPLE` and `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`.
- A value whose text is itself a placeholder — `your-key-here`, `REPLACE_ME`, `CHANGEME`, `xxx`, `dummy` — or a credential-shaped string with a documentation marker in the surrounding prose.
- High-entropy strings that are not credentials: git commit SHAs in a changelog, CSS colour literals, base64-encoded test fixtures, a UUID used as a correlation id, an integrity `sha384-` hash in a `<script>` tag.
- **Publishable** keys that are designed to be in a client: a Stripe `pk_live_`, a Firebase web `apiKey` in a `firebaseConfig` block, a public Sentry DSN. These are identifiers, not credentials — the question is whether the backend authorizes anything on them.
- A **test-mode** key is *not* in this list. `sk_test_` authenticates against a real test API, reads real test data, and is a credential whose name merely contains the word "test".
## Reference files
Read these only when the task calls for them.
- `references/verifying-findings.md`
Scanned 9/6/2026
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!