Checklist d'audit des permissions Claude Code: vérifier allow/deny en 5 minutes
Auditez allow/deny, commandes risquées, variables d'environnement et logs Claude Code chaque matin en 5 minutes.
L’audit fixe ce que Claude Code peut faire aujourd’hui
Le scénario le plus risqué n’est pas toujours “tout autoriser”. Le cas le plus courant est plus discret : hier, vous avez autorisé Bash(git push *) ou un WebFetch trop large; aujourd’hui, vous ouvrez un dépôt de production sans vous rappeler que cette règle est encore active.
Cette page propose une routine matinale de cinq minutes. allow signifie exécuter sans nouvelle confirmation, ask signifie demander validation, et deny signifie bloquer. Pour débuter, voyez ces règles comme les bords du bureau que vous donnez à l’agent.
Au 3 juin 2026, la documentation officielle indique que /permissions affiche les permissions d’outils et le fichier source. Les règles sont évaluées dans l’ordre deny -> ask -> allow, donc deny prévaut. Vérifiez toujours les pages officielles Claude Code Permissions, Settings et Environment variables.
Placez cette routine après la checklist des 30 premières minutes et avant le setup d’équipe avec le modèle CLAUDE.md. Le but n’est pas d’ajouter de la bureaucratie, mais de rendre le travail assez petit pour être relu.
Le flux en cinq minutes
Commencez par le risque de la tâche du jour, pas par le JSON. Documentation, dépendances, formulaires et déploiement n’ont pas besoin des mêmes limites.
flowchart TD
A[Start session] --> B[Check git status]
B --> C[Open /permissions]
C --> D[Review allow / ask / deny]
D --> E[Inspect env and logs policy]
E --> F[Run local audit script]
F --> G[Write handoff note]
| Où regarder | À vérifier | Signal d’alerte |
|---|---|---|
git status --short | Des changements existent déjà | Un diff existe sans propriétaire clair |
/permissions | Quelle source fournit chaque règle | Bash, WebFetch ou Edit global en allow |
.claude/settings.json | Règles partagées de l’équipe | Déploiement, billing ou liens de paiement en auto-allow |
.claude/settings.local.json | Exceptions personnelles | Une règle d’exploration d’hier reste active |
env | Historique et sous-processus | Audit demandé, mais CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 |
Une nuance officielle est importante : Bash seul dans deny retire l’outil Bash du contexte de Claude, alors qu’une règle ciblée comme Bash(rm *) garde l’outil disponible et bloque seulement les appels correspondants. Une consigne dans CLAUDE.md guide le modèle, mais n’impose pas une barrière technique.
Exemple minimal de settings repo
Les paramètres partagés fonctionnent mieux quand les actions risquées sont bloquées tôt et que les décisions restent dans ask. Ce bloc est une base pratique pour .claude/settings.json.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"Bash(git status *)",
"Bash(git diff *)",
"Read(./src/**)",
"Read(./docs/**)"
],
"ask": [
"Bash(npm install *)",
"Bash(pnpm add *)",
"Bash(git push *)",
"Bash(npm run deploy *)",
"Edit(./.github/**)"
],
"deny": [
"Bash(curl *)",
"Bash(wget *)",
"Bash(rm -rf *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"WebFetch(domain:pastebin.com)"
],
"defaultMode": "default",
"disableBypassPermissionsMode": "disable"
},
"env": {
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1"
}
}
Ici, “harness” veut dire le support de travail de l’agent : Claude Code, settings, hooks, sandbox et attentes de logs ensemble. On ne demande pas simplement plus de confiance; on donne un périmètre plus clair.
Bash(npm run test *) utilise un joker. La documentation actuelle reconnaît aussi un :* final, par exemple Bash(ls:*), mais seulement en fin de motif. Pour une équipe, Bash(git push *) est plus lisible.
Checklist repo à copier
L’audit doit rester court. Collez ce bloc dans une PR, une issue ou une note de passage.
claude_code_permission_audit:
date: "2026-06-03"
repository:
name: "your-repo"
branch: "feature/your-task"
dirty_before_start: "yes/no"
allowed_today:
- "Read project files"
- "Edit MDX and test files"
- "Run npm run lint"
- "Run npm run test -- --runInBand"
ask_before:
- "Install or update packages"
- "Change auth, billing, analytics, or deploy config"
- "Push commits or create releases"
never_allow:
- "Print .env, tokens, cookies, or private keys"
- "Run curl/wget for arbitrary URLs"
- "Delete git history or force-push"
proof_required:
- "git diff reviewed"
- "test or build command captured"
- "rollback note written"
owner_handoff:
reviewer: "name"
open_questions:
- "Which production URL should be checked?"
La ligne importante est allowed_today. Elle ne donne pas un droit permanent; elle définit le minimum nécessaire pour finir la tâche du jour avec preuve.
Détecter les motifs dangereux avec Node
Une revue visuelle manque facilement un Bash global ou un Bash(npx *) oublié. Enregistrez ceci dans scripts/audit-claude-permissions.mjs et lancez-le à la racine du dépôt.
#!/usr/bin/env node
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const repo = process.cwd();
const settingsFiles = [
path.join(os.homedir(), ".claude", "settings.json"),
path.join(repo, ".claude", "settings.json"),
path.join(repo, ".claude", "settings.local.json"),
].filter((file) => fs.existsSync(file));
const riskyAllowRules = [
{ pattern: /^Bash$/i, severity: "high", reason: "all Bash commands are auto-allowed" },
{ pattern: /^PowerShell$/i, severity: "high", reason: "all PowerShell commands are auto-allowed" },
{ pattern: /^(Edit|Write)$/i, severity: "high", reason: "all file edits are auto-allowed" },
{ pattern: /^WebFetch$/i, severity: "medium", reason: "all web fetches are auto-allowed" },
{
pattern: /^Bash\((curl|wget|nc|ncat|ssh|scp|rsync)\b.*\)$/i,
severity: "high",
reason: "network or transfer command is auto-allowed",
},
{
pattern: /^Bash\(.*\b(rm\s+-[^\)]*r|git\s+push|npm\s+install|pnpm\s+add|yarn\s+add|npx|docker\s+exec|devbox\s+run|mise\s+exec|terraform\s+apply|kubectl\s+apply)\b.*\)$/i,
severity: "high",
reason: "destructive or environment-changing command is auto-allowed",
},
{
pattern: /^PowerShell\(.*\b(Remove-Item|Invoke-WebRequest|Invoke-RestMethod|Start-Process)\b.*\)$/i,
severity: "high",
reason: "risky PowerShell command is auto-allowed",
},
];
const expectedDenyRules = [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)",
"Bash(wget *)",
];
const findings = [];
function add(file, severity, rule, reason) {
findings.push({ file: path.relative(repo, file) || file, severity, rule, reason });
}
function readJson(file) {
try {
return JSON.parse(fs.readFileSync(file, "utf8"));
} catch (error) {
add(file, "high", "JSON", `cannot parse settings: ${error.message}`);
return null;
}
}
for (const file of settingsFiles) {
const settings = readJson(file);
if (!settings) continue;
const permissions = settings.permissions ?? {};
const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
const ask = Array.isArray(permissions.ask) ? permissions.ask : [];
const deny = Array.isArray(permissions.deny) ? permissions.deny : [];
if (permissions.defaultMode === "bypassPermissions") {
add(file, "high", "permissions.defaultMode", "session starts in bypassPermissions");
}
if (permissions.disableBypassPermissionsMode !== "disable") {
add(file, "medium", "permissions.disableBypassPermissionsMode", "bypass mode is not disabled here");
}
if (settings.env?.CLAUDE_CODE_SKIP_PROMPT_HISTORY === "1") {
add(file, "low", "CLAUDE_CODE_SKIP_PROMPT_HISTORY", "prompt history and transcripts are not written");
}
if (settings.env?.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB !== "1") {
add(file, "low", "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB", "subprocess credential scrubbing is not enabled here");
}
for (const rule of allow) {
for (const risky of riskyAllowRules) {
if (risky.pattern.test(rule)) add(file, risky.severity, rule, risky.reason);
}
}
for (const required of expectedDenyRules) {
if (!deny.includes(required)) add(file, "low", required, "consider adding this deny rule");
}
if (ask.length === 0) {
add(file, "low", "permissions.ask", "no ask rules are defined");
}
for (const rule of [...allow, ...ask, ...deny]) {
if (/:\*[^)]/.test(rule)) {
add(file, "medium", rule, "the :* shorthand only behaves as a wildcard at the end of a pattern");
}
}
}
if (settingsFiles.length === 0) {
console.log("No Claude Code settings files found in user or repo scope.");
} else if (findings.length === 0) {
console.log("No risky Claude Code permission patterns found.");
} else {
console.table(findings);
}
if (findings.some((finding) => finding.severity === "high")) {
process.exitCode = 1;
}
Depuis PowerShell :
New-Item -ItemType Directory -Force -Path .\scripts | Out-Null
node .\scripts\audit-claude-permissions.mjs
Ce script n’est pas un moteur de sécurité complet. Il crée un point d’entrée de revue. Même avec Bash(curl *) bloqué, une commande Bash autorisée peut lancer un script Node qui utilise le réseau. Pour des limites plus fortes, ajoutez sandbox ou conteneur.
Quatre cas d’usage concrets
1. Articles et documentation
MDX, README, traductions et captures d’écran sont souvent moins risqués. Vous pouvez généralement autoriser Read(./src/**), Edit(./site/src/content/**), Bash(npm run lint) et Bash(npm run test *), tout en gardant npm install et git push dans ask.
Le piège est le CTA. Les liens Gumroad, formulaires de contact et URL de PDF gratuit touchent les revenus et les leads. Le contrôle d’URL publique doit donc faire partie de la preuve.
2. Mises à jour de dépendances
Une dépendance modifie package.json, lockfile, build et parfois posture de sécurité. Gardez l’installation derrière ask, puis exigez raison, commande de test et note de rollback.
Bon prompt : “Limite cela à trois candidats et montre le risque de breaking change, la commande de vérification et le rollback dans un tableau.”
3. Auth, billing et analytics
Login, Stripe, Gumroad, balises publicitaires, emails et webhooks doivent passer par une validation humaine. Les tests ne suffisent pas. Regardez quelles données partent, si un échec peut doubler une facturation et si les logs gardent des données personnelles.
CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 évite d’écrire l’historique des prompts et les transcriptions de session sur disque. C’est utile pour des sessions sensibles temporaires, mais cela réduit l’auditabilité d’équipe.
4. Passage d’équipe
Lors d’un passage de relais, laissez la trace de décision. Une bonne note dit ce qui a été autorisé, bloqué, prouvé et ce qui reste humain.
Handoff note:
- Allowed today: Edit content files, run lint, run unit tests.
- Asked before: package changes, deploy, payment links, analytics tags.
- Denied: .env reads, arbitrary curl/wget, recursive delete.
- Evidence: npm run lint passed, git diff reviewed.
- Remaining risk: production URL has not been checked after deploy.
Pièges fréquents
Premier piège : l’auto-allow trop large. Bash, PowerShell, Edit ou WebFetch complets dans allow semblent efficaces, mais déplacent trop de risque vers la mémoire et la revue humaine.
Deuxième piège : filtrer les URL seulement avec des motifs Bash. Bash(curl https://github.com *) reste fragile : options, redirections, variables et espaces peuvent changer. Bloquez curl et wget, puis utilisez WebFetch(domain:example.com) ou un hook.
Troisième piège : les wrappers. La doc décrit des wrappers intégrés comme timeout ou time, mais les runners npx, docker exec, devbox run et mise exec demandent plus de prudence.
Quatrième piège : croire que Read/Edit deny isole tout le système. Cela couvre les outils intégrés et certaines commandes reconnues, pas n’importe quel script qui ouvre un fichier en interne.
Prompt d’équipe pour le premier tour
Commencez par un audit, pas par une implémentation.
Before changing files, audit Claude Code permissions for this repository.
Return:
1. allow rules that are safe for today's task
2. ask rules that should stay behind human approval
3. deny rules that protect secrets, deploys, and destructive commands
4. environment variables that affect logs or subprocess secrets
5. the smallest task you can complete with proof and rollback notes
Do not edit files until the audit is summarized.
Le prompt n’impose pas la sécurité à lui seul. Les settings et l’interface de permissions le font. Sa valeur est de rendre la limite visible avant la première modification.
Protéger le chemin de revenu
Pour un site qui mène vers un PDF gratuit, des produits Gumroad ou de la consultation, l’audit protège aussi les revenus. Pour stabiliser le flux de base, commencez par la cheatsheet gratuite. Pour organiser CLAUDE.md, permissions, hooks et MCP en équipe, le Setup Guide est plus rapide. Pour un déploiement accompagné, consultez la page formation et consultation.
Après l’avoir testé en pratique, la routine la plus utile a été de vérifier git status, /permissions, .claude/settings.local.json et le script avant toute modification. Garder les liens Gumroad et le déploiement dans ask ralentit un peu la session, mais accélère la revue car chaque changement lié au revenu garde une raison d’approbation visible.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Checklist d'audit de dépôt Claude Code avant la première modification
Auditer un dépôt en 20 minutes: périmètre, zones risquées, commandes de preuve et CTA revenus.
Claude Code Harness Lite : une petite structure pour changer sans dériver
Un workflow débutant pour séparer lecture, modification, preuve, URL publique et CTA de revenus.
Premier repo map avec Claude Code : lire un code existant sans brûler le contexte
Workflow sûr pour lire un dépôt avec Claude Code : carte, petites tâches, preuves, PDF gratuit, Gumroad et consultation.