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-f91d1d00)More formats (shields.io, HTML) on the badges page.
---
id: secret-detection
version: "2.0.0"
title: "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."
category: prevention
severity: critical
applies_to:
- "when generating code that reads or passes a credential"
- "when creating .env, config templates, or CI secret wiring"
- "before committing, and when reviewing a diff that touches credentials"
- "after finding a credential in source, history, or a log"
languages: ["*"]
token_budget:
minimal: 1150
compact: 1700
full: 2050
rules_path: "checklists/"
tests_path: "tests/"
related_skills: ["logging-security", "cicd-security", "container-security", "supply-chain-security"]
last_updated: "2026-08-14"
sources:
- "OWASP Secrets Management Cheat Sheet"
- "CWE-798: Use of Hard-coded Credentials"
- "CWE-259: Use of Hard-coded Password"
- "NIST SP 800-57 Part 1 Rev. 5: Key Management"
external_tools:
- name: gitleaks
purpose: "scan the working tree"
command: "gitleaks dir ."
- name: gitleaks
purpose: "scan git history — a different question, and the one that matters after a leak"
command: "gitleaks git ."
---
# Secret Detection
## Rules (for AI agents)
### 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".
## Context (for humans)
The rule ordering is the whole skill. Everything else here is standard advice; the one
thing worth being emphatic about is that removal is not remediation, because it is the
step people reach for first and the one that does nothing. A secret that reached a
remote is public, and every minute spent rewriting history before rotating is a minute
the credential still works.
The second thing is the split between detection and prevention. Prevention is
deterministic and happens while the code is written: the value is read from the
environment, so there is nothing to detect. Detection is probabilistic — regex,
entropy, proximity — and it has both false positives and false negatives, which means
a clean scan is evidence and not proof. Skills that treat a green scanner as the goal
end up tuning the scanner.
Which literal strings count as credentials is data, not prose: it lives in
`checklists/secret_detection.yaml` with per-pattern entropy floors, hotwords and
exclusions, and it is what `scan_secrets` reads. That is why the rules above tell the
agent to run the scanner rather than reproducing a prefix list here — an inline list
is a copy that goes stale the first time the file gains a pattern.
## References
- `references/verifying-findings.md` — confirm or refute a finding, then rotate,
clean and lock it
- `checklists/secret_detection.yaml` — the pattern set the scanner reads: regexes,
prefixes, hotwords, entropy floors, and the `exclusions:` block
- `tests/corpus.json` — fixtures for validation
- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
- [CWE-798](https://cwe.mitre.org/data/definitions/798.html) — Use of Hard-coded Credentials.
- [CWE-259](https://cwe.mitre.org/data/definitions/259.html) — Use of Hard-coded Password.
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!