Getting Started (Mis à jour: 03/06/2026)

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.

Checklist d'audit des permissions Claude Code: vérifier allow/deny 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érifierSignal d’alerte
git status --shortDes changements existent déjàUn diff existe sans propriétaire clair
/permissionsQuelle source fournit chaque règleBash, WebFetch ou Edit global en allow
.claude/settings.jsonRègles partagées de l’équipeDéploiement, billing ou liens de paiement en auto-allow
.claude/settings.local.jsonExceptions personnellesUne règle d’exploration d’hier reste active
envHistorique et sous-processusAudit 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.

#claude-code #permissions #security #setup #workflow #claude-md
Gratuit

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.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.