Sécuriser les permissions de Claude Code : bloquer les écritures hors du dépôt, refuser au lieu de demander, auditer settings.local.json
Mis à jour le

En bref : placez ceci dans .claude/settings.json à la racine du dépôt, commitez-le et redémarrez Claude Code. Il faut Claude Code 2.1.319 ou plus récent (claude --version, puis claude update).
{
"permissions": {
"blockWritesOutsideWorkingDirectories": true,
"denyInsteadOfPrompting": true,
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)",
"Bash(wget *)"
]
}
}Ce que chaque ligne vous apporte :
| Ligne | Effet | Ajouté dans |
|---|---|---|
blockWritesOutsideWorkingDirectories | Les outils Write, Edit et NotebookEdit refusent tout chemin situé hors de vos répertoires de travail, dans tous les modes de permission, y compris bypassPermissions | 2.1.314 (30 octobre 2026) |
denyInsteadOfPrompting | Un appel d’outil qui attendrait une demande de permission est refusé et le tour continue, dans les sessions de terminal, les sous-agents et les coéquipiers | 2.1.319 (6 novembre 2026) |
Règles deny Read(...) | .env et secrets/ restent illisibles pour les outils de fichiers et pour les commandes shell telles que cat, head et sed qui nomment le fichier | de longue date |
Bash(curl *) / Bash(wget *) | Les requêtes réseau lancées depuis le shell sont refusées au lieu de faire l’objet d’une demande | de longue date |
J’ai testé le blocage des écritures, les règles deny et le comportement en exécution sans surveillance sur macOS avec Claude Code 2.1.319 le 8 novembre 2026, sous forme d’exécutions claude -p --output-format json avec le mode de permission défini pour chaque test. Les messages de refus exacts sont cités plus bas. Le changelog décrit denyInsteadOfPrompting pour les sessions de terminal, les sous-agents et les coéquipiers, qu’une exécution -p refuse déjà : sa description vient donc du changelog (opens in a new tab), pas d’un test. Le reste de ce guide explique pourquoi ces réglages comptent précisément maintenant, ce que chacun couvre ou ne couvre pas, et trois vérifications à effectuer une seule fois.
Pourquoi maintenant : trois incidents en neuf jours
Claude Code a publié sept versions entre le 26 octobre et le 6 novembre 2026, et trois affaires de sécurité sont tombées dans la même fenêtre. Chacune correspond à une vérification concrète.
| Date | Ce qui s’est passé | Votre vérification ponctuelle |
|---|---|---|
| 30 oct. | Phorion a découvert une build piégée de l’extension officielle Claude Code for VS Code sur le Cursor Marketplace, versions 2.1.312 et 2.1.313. Elle ajoute une clé SSH de l’attaquant à ~/.ssh/authorized_keys et installe un mécanisme de persistance (avis de sécurité (opens in a new tab), HN 1 011 points (opens in a new tab)) | Listez la version de votre extension et faites un grep sur authorized_keys, voir l’étape 5 ci-dessous |
| 5 nov. | Issue GitHub #107757 (opens in a new tab) : Claude Code plaçait l’adresse e-mail du compte dans l’en-tête User-Agent des requêtes web. Près de 1 000 réactions, toujours ouverte au 8 novembre (HN 1 597 points (opens in a new tab)) | Mettez à jour vers la 2.1.317 ou plus récente, qui demande confirmation avant qu’un outil n’envoie votre e-mail, voir l’étape 6 ci-dessous |
| 7 nov. | Apiiro a trouvé 1 122 fichiers GitHub publics dans lesquels une approbation « Yes, and don't ask again » avait enregistré dans .claude/settings.local.json une commande shell contenant un mot de passe ou un jeton (rapport (opens in a new tab), HN 500+ points (opens in a new tab)) | Lancez le script d’audit de l’étape 4 ci-dessous |
Aucun de ces problèmes n’est réglé par un mode de permission. Il faut un fichier de réglages, un audit et une vérification de version.
- Sécuriser les permissions de Claude Code : bloquer les écritures hors du dépôt, refuser au lieu de demander, auditer settings.local.json
- Convertir Python en EXE : Runcell, PyInstaller, Nuitka et cx_Freeze
- Mettre à jour pandas 3.1 : corriger inplace (Pandas4Warning), df.select() et read_csv plus rapide
- Passer à OpenCode 2.0 : migrer votre config v1, vos plugins et vos sessions
- Installer Python 3.15 avec uv : imports paresseux (lazy imports) et compatibilité pandas, PyTorch
- Tutoriel Claude Code Mods : créer, tester et installer votre premier mod, avec 15 exemples de la communauté
- GPT Image 2.5 : guide d'utilisation, Flare ou Sunburst et tarifs API
- Comment utiliser DeepSeek Harness : installation, configuration et premier agent
- Runcell Science : l'alternative open source à Claude Science pour la recherche
- Empêcher un Mac de se mettre en veille : capot fermé, Codex et Claude Code
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot : quelle stack d’agents IA choisir en 2026 ?
- Comment Claude Code analyse un notebook Jupyter en Data Science : capacités réelles et limites
- Claude Code routines : triggers, cron jobs et automatisation d’agents IA
- Claude Code Desktop : activer le mode Bypass permissions
- Comment Créer Deux Agents Python avec le Protocole A2A de Google - Tutoriel Étape par Étape
- Top 10 bibliothèques de visualisation de données en Python en pleine croissance en 2025
Étape 1 : bloquer les écritures de fichiers hors du dépôt
permissions.blockWritesOutsideWorkingDirectories fait refuser aux trois outils d’édition de fichiers tout chemin qui ne se trouve pas dans un répertoire de travail. Les répertoires de travail sont le dossier dans lequel vous avez lancé Claude Code, plus tout ce que vous avez ajouté avec /add-dir, --add-dir ou permissions.additionalDirectories dans vos réglages utilisateur ou gérés. Une entrée additionalDirectories dans le .claude/settings.json du dépôt lui-même ne lève pas le blocage. Le blocage tient dans tous les modes de permission, y compris bypassPermissions, et un true dans n’importe quel fichier de réglages l’emporte sur un false ailleurs : un dépôt peut donc l’activer pour tous ceux qui le clonent.
J’ai défini la clé dans un projet de test et demandé à Claude Code, en mode acceptEdits, de créer un fichier dans mon répertoire personnel avec l’outil Write. L’appel a été refusé avec ce message :
/Users/me/kanaries-block-test.txt is outside /path/to/proj; the
permissions.blockWritesOutsideWorkingDirectories setting blocks writes
outside the working directories. Ask the user to add the directory with
/add-dir, or to remove that setting.Le fichier n’a pas été créé, et le résultat JSON listait l’appel sous permission_denials avec tool_name: "Write".
Quatre limites à connaître avant de vous y fier :
- Il ne limite ni les commandes shell, ni les outils MCP, ni les programmes de hooks.
echo x > ~/filedepuis l’outil Bash n’est pas un appelWrite. Pour cloisonner les écritures du shell, activez le sandbox (voir la section optionnelle en fin de guide). - Certains fichiers propres à Claude Code restent accessibles en écriture : les fichiers de plan, le scratchpad de session, le répertoire
tmpd’une session en arrière-plan et les fichiers.mdde mémoire automatique du projet. C’est voulu. - Claude ne peut plus modifier aucun fichier de réglages de Claude Code, même à l’intérieur du dépôt, parce qu’un fichier de réglages pourrait lever le blocage. Modifiez
.claude/settings.jsonvous-même. - Les outils de worktree disparaissent. Quand la clé est activée, Claude Code retire
EnterWorktreeetExitWorktreeou refuse les appels à ces outils. Si vos sous-agents ont besoin de worktrees, ajoutez.claude/worktreesà la racine du dépôt comme répertoire de travail.
Son pendant, permissions.blockReadsOutsideWorkingDirectories (2.1.257 ou plus récent), fait de même pour Read, Grep, Glob et les appels LSP. Activez-le quand le dépôt ne doit pas voir le reste de votre disque.
Étape 2 : garder les secrets illisibles avec des règles deny
Une règle deny Read(path) bloque les outils de fichiers intégrés et, selon la documentation, les commandes de fichiers que Claude Code reconnaît dans Bash (cat, head, tail, sed, tee), ainsi que les redirections shell qui nomment le fichier. Elle bloque aussi Edit et Write sur le même chemin : Claude ne peut donc pas non plus écraser votre .env.
Testé : avec "deny": ["Read(./.env)"], demander à Claude de lire .env avec l’outil Read a renvoyé :
File is in a directory that is denied by your permission settings.La règle atteint aussi le shell. Dans une exécution en acceptEdits, j’ai demandé cat README.md puis cat .env : le premier a affiché le fichier, le second a été refusé avec Permission to use Bash with command cat .env has been denied. Une exécution séparée claude -p en mode par défaut a refusé curl -sI https://example.com à cause de la règle Bash(curl *). Chaque refus a été enregistré dans permission_denials, et chaque exécution s’est terminée au lieu de rester bloquée.
Trois pièges de syntaxe des règles, tirés de la référence des permissions (opens in a new tab) :
- Utilisez
Read(...)etEdit(...). Les règlesWrite(docs/**),Grep(docs/**)etGlob(...)avec un chemin sont acceptées mais ne correspondent jamais à rien. Bash(git diff *), avec une espace avant le*, correspond à toute commande commençant pargit diff.Bash(git diff*)correspondrait aussi àgit diff-index.- Une règle deny n’attrape pas une commande qui lit un fichier sans le nommer, comme
grep -r pattern .lancé depuis le dossier qui contient le secret. C’est à cela que sert le sandbox.
Un fichier .claudeignore n’a aucun effet. Déplacez ses entrées dans des règles deny Read.
Étape 3 : ne jamais rester bloqué sur une demande de permission
Il existe désormais quatre façons de faire en sorte qu’une exécution Claude Code sans surveillance refuse au lieu d’attendre. Choisissez selon l’endroit où tourne l’exécution.
| Situation | À utiliser | Comportement |
|---|---|---|
| Session de terminal interactive que vous laissez tourner seule, y compris ses sous-agents et coéquipiers | "denyInsteadOfPrompting": true dans les réglages (2.1.319) | Un appel qui attendrait une demande est refusé et le tour continue (formulation du changelog ; je n’ai pas pu le tester en mode -p, car -p refuse déjà) |
Exécution claude -p ou Agent SDK sans mode de permission défini | Rien de plus | Depuis la 2.1.302, -p démarre en mode Manual et refuse tout appel nécessitant une approbation. Testé ci-dessus |
| Job CI verrouillé | --permission-mode dontAsk | Tout appel qui déclencherait une demande est refusé (un mod que vous avez installé peut encore approuver certains appels). Les commandes en lecture seule, les lectures de fichiers dans les répertoires de travail et vos règles allow s’exécutent toujours |
Exécution avec un hôte de permissions, comme une application SDK avec canUseTool ou --permission-prompt-tool | --permission-prompts none (2.1.259 ou plus récent) | L’exécution n’attend pas l’hôte ; Claude est informé que personne ne peut approuver et qu’il ne doit pas réessayer |
Testé avec --permission-mode dontAsk --permission-prompts none : python3 -c 'print(2+2)' a été refusé avec un message commençant par Permission to use Bash has been denied because Claude Code is running in don't ask mode, tandis que git log --oneline -1 s’est exécuté parce qu’il figure sur la liste intégrée des commandes en lecture seule. Le JSON de résultat contenait une entrée dans permission_denials.
Ce qu’aucun mode ni aucune règle allow ne peut approuver, même bypassPermissions : les règles ask explicites, l’outil AskUserQuestion, les outils MCP marqués requiresUserInteraction, et les commandes rm reconnues comme visant des chemins critiques, telles que rm -rf ~. dontAsk les refuse tous d’emblée, et refuse aussi les lectures depuis des chemins réseau même quand une règle allow correspond.
Si un dépôt ne doit jamais être exécuté en mode bypass, ajoutez "disableBypassPermissionsMode": "disable" sous permissions. Claude Code rejette alors --dangerously-skip-permissions et ignore une définition de sous-agent qui demande le bypass.
Étape 4 : auditer settings.local.json à la recherche de règles allow qui fuient
Voici le mécanisme derrière le rapport d’Apiiro. Quand Claude demande à exécuter une commande shell et que vous choisissez Yes, and don't ask again, Claude Code enregistre une règle allow portant ce préfixe de commande dans .claude/settings.local.json, à la racine du dépôt. Si la commande était psql postgres://app:Sup3rSecret@db/prod -c ..., le mot de passe se trouve maintenant dans la règle.
Claude Code ajoute **/.claude/settings.local.json à votre fichier d’exclusions git global la première fois qu’il écrit ce fichier dans un dépôt qui ne l’ignore pas déjà. Sur mon Mac, ce fichier est ~/.config/git/ignore, et le motif se trouve à la ligne 1. C’est pourquoi git add .claude/settings.local.json échoue ici avec « ignored by one of your .gitignore files ». Mais la protection est par machine, pas par dépôt. Un fichier que vous avez créé à la main avant que Claude Code n’y écrive, un dépôt copié sur une autre machine comme simple répertoire plutôt que cloné, ou un sandbox sans vos exclusions globales : tous commitent ce fichier comme n’importe quel autre. L’auteur du rapport Apiiro a indiqué sur HN que, dans 539 des 1 105 dépôts retracés, un commit co-signé par Claude avait modifié le fichier.
Lancez ceci depuis la racine du dépôt. Le script trouve chaque .claude/settings*.json, indique si git le suit et signale les règles allow qui contiennent des identifiants ou qui approuvent des familles d’outils entières.
cat > /tmp/claude-settings-audit.sh <<'EOF'
#!/usr/bin/env bash
set -u
root="${1:-.}"
found=0
while IFS= read -r -d '' f; do
found=1
echo "== $f"
if git -C "$(dirname "$f")" ls-files --error-unmatch "$(basename "$f")" >/dev/null 2>&1; then
echo " TRACKED BY GIT <- settings.local.json should never be"
fi
grep -nE '"(Bash|PowerShell)\([^"]*(password|passwd|token|secret|api[_-]?key|Authorization|Bearer |PGPASSWORD|AWS_SECRET|--password|://[^"/]*:[^"@]*@|[A-Z_]{3,}=[^[:space:]"]{8,})' "$f" \
| sed 's/^/ SECRET-LIKE: /'
grep -nE '"(Bash|PowerShell)(\(\*\))?"|"Bash\((sudo|rm|curl|wget|ssh|scp|git push|npm publish|docker)[^"]*\*\)"' "$f" \
| sed 's/^/ BROAD: /'
done < <(find "$root" -path '*/node_modules' -prune -o -type f \
\( -name 'settings.local.json' -o -name 'settings.json' \) -path '*/.claude/*' -print0 2>/dev/null)
[ "$found" = 0 ] && echo "No .claude/settings*.json under $root"
EOF
bash /tmp/claude-settings-audit.sh .Sur un fichier synthétique de six règles, il a signalé les trois qui embarquaient un mot de passe de base de données, un jeton bearer et une affectation DATABASE_URL=..., plus Bash(*), Bash(rm -rf *) et, une seconde fois sous BROAD, la règle curl. Quand le fichier était commité dans un dépôt de test, il a aussi affiché la ligne TRACKED BY GIT. C’est un grep : attendez-vous à relire les résultats vous-même.
Que faire en cas de résultat :
- Faites d’abord tourner l’identifiant. Si le fichier a déjà été poussé, considérez le secret comme public. Réécrire l’historique ne suffit pas dès qu’un fork ou un scraper l’a récupéré.
- Supprimez la règle, ou remplacez-la par une règle qui ne porte pas le secret : approuvez
psql *et passez le mot de passe viaPGPASSWORDdepuis l’environnement de votre shell, pas dans la commande. - Si git suit le fichier, lancez
git rm --cached .claude/settings.local.jsonet ajoutez.claude/settings.local.jsonau.gitignoredu dépôt, pour que la protection voyage avec le dépôt au lieu de dépendre des exclusions globales de chaque machine. - Vérifiez aussi
.claude/settings.json. Il est destiné à être commité : une règle allow contenant un secret y est donc une fuite par conception, pas par accident.
Pour la même raison, préférez les règles deny et ask dans le fichier commité et gardez vos règles allow personnelles en local. Les règles deny et ask s’appliquent immédiatement ; les règles allow venant d’un dépôt ne s’appliquent qu’une fois que chaque coéquipier a fait confiance au dossier.
Étape 5 : vérifier votre extension IDE et vos clés SSH
Les builds piégées étaient les versions 2.1.312 et 2.1.313 de l’extension Claude Code for VS Code distribuée via le Cursor Marketplace, signalées par Phorion le 30 octobre. Cursor les a retirées. Selon Phorion, la charge s’exécute dès le chargement du module de l’extension, ajoute une clé Ed25519 portant le commentaire svc-telemetry à ~/.ssh/authorized_keys, tente d’activer Remote Login et envoie des informations sur l’hôte à un serveur distant. Sur macOS, l’étape d’activation de SSH échoue pour un utilisateur non administrateur à cause d’un bug dans l’implant, mais la clé et le mécanisme de persistance sont tout de même déposés.
Listez les versions installées :
cursor --list-extensions --show-versions | grep -i claude
code --list-extensions --show-versions | grep -i claude
ls ~/.cursor/extensions ~/.vscode/extensions 2>/dev/null | grep -i claudeSur ma machine, cela a renvoyé anthropic.claude-code@2.1.302, hors de la plage affectée. Vérifiez ensuite l’indicateur publié par Phorion :
grep -n "svc-telemetry" ~/.ssh/authorized_keys 2>/dev/null || echo "no match"Phorion précise que la chaîne de commentaire est contrôlée par l’attaquant : un grep sans résultat n’est donc pas une preuve. Si vous avez exécuté la 2.1.312 ou la 2.1.313 depuis le Cursor Marketplace, supprimez de authorized_keys toute clé que vous ne reconnaissez pas, passez en revue les éléments de connexion et les launch agents, et considérez la machine comme compromise jusqu’à ce qu’une réponse à incident l’ait examinée. Installez l’extension depuis le VS Code Marketplace, ou laissez la CLI claude l’installer via /ide ; depuis la 2.1.318, Claude Code n’installe plus et ne met plus à jour l’extension de lui-même depuis un terminal d’IDE.
Étape 6 : le correctif de l’e-mail dans le User-Agent
L’issue #107757 signale que Claude Code envoyait l’adresse e-mail du compte dans l’en-tête User-Agent des requêtes web effectuées lors des recherches et des fetchs, de sorte que des sites et des traceurs pouvaient la collecter. L’entrée du changelog 2.1.317, datée du 3 novembre, dit : « Added a check that asks before a web or shell tool call sends your account email address to the network. » Le rapporteur a ouvert l’issue sur la 2.1.318, et elle était toujours ouverte avec près de 1 000 réactions au 8 novembre : surveillez-la pour connaître la résolution finale.
Ce que vous pouvez faire dès aujourd’hui : mettre à jour (claude update) et, si vous exécutez sans surveillance, savoir qu’avec denyInsteadOfPrompting ou dontAsk cette nouvelle vérification « demande avant d’envoyer » devient un refus, ce qui est le comportement souhaité.
Ce que chaque garde-fou arrête : testé vs documenté
| Tentative | blockWrites… | Règle deny Read | Deny Bash(curl *) | dontAsk / -p par défaut | Sandbox |
|---|---|---|---|---|---|
L’outil Write crée ~/x.txt | Refusé (testé) | — | — | Demande → refus | Autorisé par le sandbox, les outils de fichiers sont hors de son périmètre |
L’outil Read lit .env | — | Refusé (testé) | — | Autorisé, les lectures n’ont pas besoin d’approbation | — |
cat .env dans Bash | — | Refusé (testé) | — | Refusé | — |
echo x > ~/x.txt dans Bash | Non couvert | — | — | Demande → refus | Bloqué (docs : Operation not permitted sur macOS) |
curl https://… dans Bash | — | — | Refusé (testé) | Refusé | Bloqué sauf si l’hôte est autorisé |
python3 -c … dans Bash | — | — | — | Refusé (testé) | S’exécute dans le sandbox |
git log, ls, autres commandes en lecture seule | — | — | — | S’exécute (testé) | S’exécute |
rm -rf ~ | — | — | — | Refusé, aucune règle ne peut l’approuver | Bloqué, le répertoire personnel est hors de l’ensemble inscriptible (docs) |
« Testé » signifie que je l’ai exécuté sur la 2.1.319 le 8 novembre 2026. Tout le reste vient de la documentation officielle liée dans ce guide.
Optionnel : mettre aussi le shell en sandbox
Les réglages ci-dessus cloisonnent les outils de fichiers propres à Claude. Les commandes shell sont cloisonnées par le sandbox Bash (opens in a new tab), désactivé par défaut. Il s’appuie sur Seatbelt sous macOS, et sous Linux ou WSL2 il nécessite bubblewrap et socat. Activez-le pour un seul projet avec /sandbox dans une session, ou pour tous les projets en ajoutant ceci à ~/.claude/settings.json :
{
"sandbox": {
"enabled": true
}
}Pour confirmer qu’il fonctionne, demandez à Claude d’exécuter touch ~/sandbox-probe. Dans le sandbox, la commande échoue avec Operation not permitted sous macOS ou Read-only file system sous Linux. Si Claude propose de relancer la commande hors du sandbox, refusez.
Une configuration combinée couvre le trou de la matrice ci-dessus : outils de fichiers cloisonnés par blockWritesOutsideWorkingDirectories, shell cloisonné par le sandbox, secrets cloisonnés par des règles deny Read, et exécutions sans surveillance cloisonnées par denyInsteadOfPrompting. Le mode bypass ne sert alors plus qu’à accélérer les demandes qui restent. Si vous avez encore besoin du bypass pour une tâche confinée, le guide du mode bypass permissions couvre l’interrupteur et ses messages d’erreur.
FAQ
Guides associés
- Claude Code Desktop : activer le mode Bypass permissions
- Tutoriel Claude Code Mods : créer, tester et installer votre premier mod
- Claude Code routines : triggers, cron jobs et automatisation d’agents IA
- Parallel Code Agents expliqués : worktrees, sandboxes et modèles d’outils desktop
- Passer à OpenCode 2.0 : migrer votre config v1, vos plugins et vos sessions