Skip to content
Back to skills

Secret Detection

FSecurity

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.

  • 22 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 6, 2026
ai-agentsgodockerawsgcpgitapibackendsecuritydocumentation

Works with

  • cli
  • api

Security analysis

F0/100
  • criticalReads or references SSH private keys
  • criticalReads or references SSH private keys
  • criticalReads or references SSH private keys
  • highContains patterns that look like hardcoded API keys
  • highContains patterns that look like hardcoded API keys

Pro scans all 4 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add ShieldNet-360/secure-vibe --skill secret-detection --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Secret Detection?

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

Security grade badge for Secret Detection
[![Security: F — Skills Directory](https://www.skillsdirectory.com/api/skills/shieldnet-360-secret-detection-f91d1d00/badge)](https://www.skillsdirectory.com/skills/shieldnet-360-secret-detection-f91d1d00)

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
---
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.

Files in this skill

  • SKILL.md7.9 KB
  • checklists/secret_detection.yaml30.4 KB
  • references/verifying-findings.md2.5 KB
  • tests/corpus.json57 KB

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.