Secret Detection

SkillDev tools

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.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Secret Detection skill

What this skill tells your AI

The instructions your AI receives, as published by shieldnet-360/secure-vibe in skills/secret-detection/SKILL.md and read by ahel’s review.

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
  • CWE-798 — Use of Hard-coded Credentials.
  • CWE-259 — Use of Hard-coded Password.

Signals

GitHub stars
22
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
secret-detection-shieldnet-360
Source
github.com/shieldnet-360/secure-vibe