Scanning for exposed secrets
secret-scanFREEsecuritysecrets
Looks at both the git history and the built bundle: two different leaks, and the second is noticed later.
Ce qu'il fait
- Triggers before a first push, before making a repository public, and on any mention of keys or environment variables.
- Searches the history, not only the working tree: a deleted line stays in git and comes back with one command.
- Checks that .gitignore is doing anything at all: it has no effect on a file git is already tracking.
- Looks separately at the built bundle. Anything with a client prefix — NEXT_PUBLIC_, VITE_, REACT_APP_ — is public by definition and protected by nothing.
- Ranks keys by consequence: a publishable payment key is meant to be public; a key that bypasses row-level security exposes every user's data.
- On a real leak, demands rotation first rather than deletion: anything that reached a public repository, a chat or a bundle must be treated as known to others, and rewriting history does not un-know it.
- Never asks for a key to be pasted for checking, and never echoes a found value — only the file and the line.
À quoi il sert
Everyone knows about leaks in git history; fewer think about the bundle, where a client-prefixed key ships to every visitor while looking like an ordinary environment variable. The response order is usually wrong too: the line gets deleted and the key left working — while it is already held by whoever read the repository before you.
Où le placer
- 1Créez le dossier .claude/skills/secret-scan dans votre projet
- 2Placez-y un fichier SKILL.md avec le texte ci-dessous
- 3C'est tout. Claude Code charge le skill lui-même quand une tâche correspond à la description
Pour que le skill soit disponible dans tous vos projets et pas un seul, placez-le dans ~/.claude/skills au lieu du dossier du projet.
Fichier SKILL.md
--- name: secret-scan description: Check that no keys, tokens or private data are about to be committed or exposed to the browser. Use before a first push, before making a repository public, or when the user mentions API keys, environment variables or a leak. --- # Checking for exposed secrets Two different problems, both called a leak: 1. A secret committed to git. It stays in the history after you delete it from the file. 2. A secret shipped to the browser. It is in the bundle, readable by anyone who opens the page. Check for both. ## In the repository Search the working tree and the history — deleting the line does not remove it from git: ``` git log -p --all -S 'BEGIN PRIVATE KEY' ``` Look for: private keys, `service_role` or admin keys, tokens with a recognisable prefix, database URLs containing a password, `.env` files that are not `.env.example`, and dumps or backups. Then check `.gitignore` actually covers them, and that no `.env` is already tracked — `.gitignore` does nothing for a file git is already following. ## In the browser bundle Anything prefixed for client exposure is public. In Next.js that is `NEXT_PUBLIC_`, in Vite `VITE_`, in Create React App `REACT_APP_`. A key with one of those prefixes is not protected by anything. Build, then grep the output for the values themselves, not the names: ``` grep -r "sk_live\|service_role" .next/static 2>/dev/null ``` Ask of each one: does this key allow more than the person holding it should have? A publishable payment key is designed to be public. A service key that bypasses row-level security is not, and a single line of it in a bundle exposes every user's data. ## When something is already exposed Say it plainly and in this order: 1. **Rotate the key first.** Not delete the line — rotate. Anything that reached a public repository, a chat, or a bundle must be considered known to others. Rewriting history does not un-know it; forks and caches keep copies. 2. Then remove it from the code and move it to environment variables. 3. Then check the provider's logs for use you did not make. Never ask for the key to be pasted so you can check it, and never echo a value you found into the reply. Report the file and the line. ## Also check Logs that print request bodies or headers. An error handler that dumps the whole config on failure. A signature-check failure that logs the expected digest. Those leak the same secrets more quietly.