
Un settings.json Claude Code ne se dégrade pas d'un coup. Il grossit d'une
règle à la fois, à chaque fois qu'on répond « ne plus me demander » à une
question qui paraissait anodine. Au bout de quelques mois, le fichier pèse
plusieurs centaines de kilo-octets, contient des milliers de règles que
personne ne relit, et parfois un mot de passe en clair au milieu d'une
commande approuvée six semaines plus tôt.
Ce n'est pas un défaut de discipline, c'est une conséquence du fonctionnement. La documentation officielle est explicite : « Permission rules behave differently because they merge across scopes rather than override ». Les règles de permission fusionnent entre les portées au lieu de s'écraser. Rien ne remplace, rien n'expire, rien ne nettoie. Le fichier ne peut que croître.
Ce guide part de ce mécanisme, montre ce que chaque réponse du dialogue de
permission écrit réellement, comment un secret y entre sans qu'on le
remarque, ce que deny protège vraiment, et comment auditer puis
reconstruire une configuration tenable.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Le dialogue de permission : ce que « ne plus demander » écrit, et où
- Pourquoi les règles s'accumulent : la fusion entre portées
- Comment un secret entre dans la configuration sans qu'on le voie
- Ce que
denyprotège, et ce qu'il ne protège pas - Auditer : les outils existants, ce qu'ils trouvent et ce qu'ils ratent
- Reconstruire une base saine et éviter la rechute
Prérequis
Section intitulée « Prérequis »- Claude Code installé et utilisé sur au moins un projet (installation).
- La structure des fichiers de configuration comprise : portées, syntaxe des règles, différence entre fichier partagé et fichier local. Elle est traitée dans settings.json avancé et permissions par projet, que ce guide complète du côté sécurité.
Le dialogue de permission : ce que chaque réponse écrit
Section intitulée « Le dialogue de permission : ce que chaque réponse écrit »Tout commence là. Quand Claude Code demande l'autorisation d'exécuter une commande, les réponses n'ont ni la même portée ni la même durée de vie, et cette différence n'est pas affichée à l'écran.
| Type d'outil | Approbation demandée | Effet de « ne plus demander » |
|---|---|---|
| Lecture seule | Non, dans les répertoires de travail | Sans objet |
| Commandes Bash | Oui, sauf un jeu de commandes en lecture seule | Permanent, par dépôt et par commande |
| Modification de fichier | Oui | Jusqu'à la fin de la session |
La ligne du milieu est celle qui remplit les fichiers. Une approbation
permanente est écrite sur le disque, dans .claude/settings.local.json à la
racine du dépôt git. Une approbation de modification de fichier, elle, n'écrit
rien : elle disparaît quand la session se termine.
Autrement dit, la case qu'on coche machinalement dix fois par jour sur des commandes shell est la seule qui laisse une trace définitive sur le disque.
Une commande composée écrit plusieurs règles
Section intitulée « Une commande composée écrit plusieurs règles »Le point le plus contre-intuitif. Approuver définitivement une commande enchaînée ne produit pas une règle, mais une par sous-commande : « When you approve a compound command with "Yes, don't ask again", Claude Code saves a separate rule for each subcommand that requires approval, rather than a single rule for the full compound string ». La documentation précise la borne : jusqu'à cinq règles pour une seule approbation.
Un cd projet && npm install && npm test approuvé une fois peut donc écrire une
règle Read pour le répertoire, une pour npm install, une pour
npm test. En une frappe, trois lignes de plus dans le fichier.
Pourquoi le fichier devient ingérable
Section intitulée « Pourquoi le fichier devient ingérable »Les réglages ordinaires suivent une précédence classique : managed
l'emporte sur les arguments de ligne de commande, qui l'emportent sur local,
puis project, puis user. Le plus prioritaire gagne, les autres sont
ignorés.
Les permissions échappent à cette règle. Elles fusionnent. Une règle écrite dans le fichier utilisateur ne sera jamais remplacée par une règle de projet : les deux coexistent et s'additionnent. Multipliez par le nombre de dépôts et par les mois d'usage, et l'ordre de grandeur devient celui-ci, mesuré sur une installation réelle :
python3 -c "import json,sys; d=json.load(open('$HOME/.claude/settings.json')); \print(len(d.get('permissions',{}).get('allow',[])), 'regles allow')"1917 regles allowPour 219 Ko de fichier et 291 préfixes de commandes distincts. Trois cents
intentions réelles, exprimées en presque deux mille lignes, parce que chaque
variante d'une même commande a produit sa propre entrée : kubectl get pods -n argocd et kubectl get pods -n argocd -o wide sont deux règles différentes.
Personne ne relit deux mille règles. C'est précisément ce qui rend le fichier dangereux : il devient un endroit où des choses s'accumulent sans regard, y compris ce qui n'aurait jamais dû y entrer.
Comment un secret entre dans la configuration
Section intitulée « Comment un secret entre dans la configuration »Voici le scénario, et il n'a rien d'exotique. Vous lancez une commande qui porte une variable d'environnement en préfixe, comme on le fait tous les jours avec un outil de migration ou un client de base de données :
DATABASE_URL=postgresql://app:motdepasse@localhost:5432/app npx prisma migrate devClaude Code demande l'autorisation. Vous répondez « ne plus demander », parce que vous allez rejouer cette migration dix fois. La règle enregistrée contient la ligne de commande complète, mot de passe compris. Elle est maintenant dans un fichier JSON, en clair, et elle y restera.
Le même mécanisme attrape les jetons passés en variable, les en-têtes
Authorization d'un curl, les clés d'API en argument. Sur l'installation
auditée pour ce guide, deux secrets ont été retrouvés de cette façon : une
URL PostgreSQL avec son mot de passe, et un secret client OIDC.
La parade est simple et tient à l'habitude : sortir le secret de la ligne de
commande avant de lancer quoi que ce soit. Un fichier .env chargé par
l'outil, une variable exportée dans le shell, ou un gestionnaire de secrets. La
commande approuvée ne contient alors qu'un nom de variable.
Empêcher le secret d'entrer plutôt que le retrouver après
Section intitulée « Empêcher le secret d'entrer plutôt que le retrouver après »Auditer, c'est constater. Le fichier contient déjà le secret, il est déjà sur le disque, il est déjà dans vos sauvegardes. La seule mesure qui protège vraiment consiste à refuser la commande avant qu'elle soit approuvée.
Claude Code le permet avec un hook PreToolUse sur Bash. Le hook reçoit la
commande en JSON sur son entrée standard, et peut répondre deny avec une
explication qui s'affiche à l'écran.
Aucun détecteur ne suffit seul
Section intitulée « Aucun détecteur ne suffit seul »C'est le point à connaître avant d'écrire le hook. Voici ce que gitleaks 8.30.0 rend sur des lignes de commande, mesuré :
| Commande testée | gitleaks |
|---|---|
GITHUB_TOKEN=ghp_… | bloque |
STRIPE_KEY=sk_live_… | bloque |
CLIENT_SECRET=8f3d9a2b… | bloque |
Authorization: Bearer eyJ… | bloque |
DATABASE_URL=postgresql://app:motdepasse@db:5432/app | laisse passer |
MYAPP_PASSWORD=hunter2ButLonger | laisse passer |
gitleaks excelle sur les formats reconnaissables, ceux des fournisseurs.
Il laisse passer le mot de passe générique, qui n'a aucune forme
particulière. Or c'est précisément celui qu'on retrouve dans les
settings.json : une URL de base de données de développement, un identifiant
de lab.
La parade tient en une expression régulière, qui attrape exactement ce que gitleaks rate :
grep -qE '://[^/ :]+:[^@/ ]{3,}@'Trois détecteurs en cascade, du moins cher au plus cher : l'URL avec identifiants, la variable sensible affectée en clair, puis gitleaks pour tout le reste.
#!/usr/bin/env bashset -uo pipefail
commande=$(cat | jq -r '.tool_input.command // empty')[ -z "$commande" ] && exit 0motif=""
if printf '%s' "$commande" | grep -qE '://[^/ :]+:[^@/ ]{3,}@'; then motif="un mot de passe dans une URL"elif printf '%s' "$commande" \ | grep -qE '\b[A-Z_]*(TOKEN|SECRET|PASSWORD|APIKEY|API_KEY)[A-Z_]*=[^ ]{6,}'; then motif="une variable sensible affectee en clair"fi
# gitleaks coute environ 300 ms au demarrage : on ne le lance que si la# commande porte au moins un indice de secret.## La garde `command -v` n'est PAS facultative : sans elle, un gitleaks absent# rend « command not found », donc un code non nul, et le `||` conclurait a un# secret sur TOUTE commande contenant un `=`.INDICES='=|://|-----BEGIN|[Aa]uthorization|[Bb]earer|[Tt]oken|[Ss]ecret|[Kk]ey|[Pp]ass'if [ -z "$motif" ] && command -v gitleaks >/dev/null 2>&1 \ && printf '%s' "$commande" | grep -qE "$INDICES"; then printf '%s' "$commande" | gitleaks stdin --no-banner --redact >/dev/null 2>&1 \ || motif="un secret reconnu par gitleaks"fi
[ -z "$motif" ] && exit 0
jq -n --arg r "Commande refusee : elle contient $motif. L'approuver en « ne plusdemander » ecrirait le secret en clair dans settings.local.json. Sortez-le de laligne de commande, puis relancez." '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $r }}'La déclaration se fait dans ~/.claude/settings.json :
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.claude/hooks/bloque-secrets.sh" } ] } ] }}Ce que ça coûte, et ce que ça donne
Section intitulée « Ce que ça coûte, et ce que ça donne »Le pré-filtre n'est pas une coquetterie : le hook s'exécute avant chaque
commande Bash. Sans lui, chaque git status payait le démarrage de gitleaks.
| Version | Temps par commande |
|---|---|
| Sans pré-filtre | 344 ms |
| Avec pré-filtre | 8 ms |
Sur huit cas de test, les quatre commandes portant un secret sont refusées et
les quatre commandes légitimes passent, y compris NODE_ENV=production npm run build, DATABASE_URL=$(cat .env.local) npx prisma migrate et
psql "$DATABASE_URL". Ces trois dernières sont exactement la bonne
pratique : le secret n'est plus dans la ligne de commande, seulement son nom.
Ce que deny protège vraiment
Section intitulée « Ce que deny protège vraiment »deny est la seule liste qui bloque. Elle mérite d'être écrite à la main, et
soigneusement, parce que deux détails de syntaxe changent tout.
La correspondance exacte ne couvre presque rien
Section intitulée « La correspondance exacte ne couvre presque rien »Une règle comme Bash(bash) ne bloque que la commande nue. Elle laisse
passer bash script.sh, qui est pourtant l'usage réel. Pour couvrir un
préfixe, la syntaxe est Bash(bash:*).
{ "permissions": { "deny": [ "Bash(bash:*)", "Bash(sudo:*)", "Read(//**/.env)", "Read(~/.ssh/**)", "Read(~/.aws/credentials)" ] }}Les liens symboliques ne suivent pas la même règle
Section intitulée « Les liens symboliques ne suivent pas la même règle »Le traitement est volontairement asymétrique, et c'est une bonne conception :
une règle allow ne s'applique que si le lien et sa cible correspondent
tous les deux, alors qu'une règle deny s'applique dès que l'un des deux
correspond. Un lien symbolique placé dans un répertoire autorisé mais pointant
à l'extérieur déclenche donc une demande, il ne passe pas en silence.
Les trois fichiers et le piège du fichier local
Section intitulée « Les trois fichiers et le piège du fichier local »| Fichier | Portée | Versionné |
|---|---|---|
~/.claude/settings.json | Toutes vos sessions, tous vos projets | Non |
.claude/settings.json | Le dépôt, pour toute l'équipe | Oui |
.claude/settings.local.json | Le dépôt, pour vous seul | Non, gitignoré automatiquement |
Claude Code configure git pour ignorer le fichier local qu'il crée lui-même. Un fichier local créé à la main n'hérite pas de cette protection, et c'est par là que des règles personnelles finissent commitées.
Le piège moins connu concerne la confiance accordée à l'espace de travail. La
documentation note que les règles allow du fichier local prennent effet « sans
l'étape de confiance qu'exigent celles de .claude/settings.json », mais cette
formulation demande deux nuances importantes.
D'abord, elle ne vaut plus telle quelle : depuis la version 2.1.207, dans un
dossier que vous n'avez pas encore approuvé, les règles allow du fichier local
passent par le même contrôle de confiance que celles du projet, jusqu'à
acceptation du dialogue. Deux exceptions subsistent, hors dépôt git et dans votre
propre répertoire de configuration.
Ensuite, si le dépôt fournit lui-même le fichier, par exemple en le commitant, la confiance d'espace de travail s'applique de nouveau. C'est précisément le scénario des vulnérabilités traitées dans Sécuriser Claude Code.
En entreprise, la réponse propre existe : allowManagedPermissionRulesOnly,
disponible uniquement en réglages administrés, neutralise toutes les règles
allow, ask et deny définies au niveau utilisateur et projet. Seules les
règles administrées s'appliquent.
Auditer sa configuration
Section intitulée « Auditer sa configuration »Ce qu'un outil dédié apporte
Section intitulée « Ce qu'un outil dédié apporte »AgentShield est un auditeur généraliste qui fonctionne sous Linux. Il découvre ~/.claude/ seul et note la configuration.
npx ecc-agentshield scan Grade: C (70/100)
Score Breakdown Secrets ██████████░░░░░░░░░░ 50 Permissions ░░░░░░░░░░░░░░░░░░░░ 0 Hooks ████████████████████ 100 MCP Servers ████████████████████ 100Il est solide sur les permissions trop larges, les hooks et les serveurs MCP,
dont il vérifie les noms contre des typosquats connus. Son mode d'analyse par
modèle est optionnel : sans ANTHROPIC_API_KEY, il refuse de démarrer, donc
un scan ordinaire n'envoie pas votre configuration à une API.
Les vérifications à faire soi-même
Section intitulée « Les vérifications à faire soi-même »Trois commandes couvrent l'essentiel de ce que l'outil ne voit pas.
Chercher les secrets, en commençant par le motif qui rapporte le plus, une paire identifiant et mot de passe dans une URL :
grep -nE '://[^/ :]+:[^@/ ]{3,}@' ~/.claude/settings.jsonCompter la dérive, pour la surveiller dans le temps plutôt que la découvrir :
python3 -c "import json; d=json.load(open('$HOME/.claude/settings.json')); \p=d.get('permissions',{}); print({k: len(v) for k,v in p.items()})"{'allow': 1917, 'deny': 10, 'ask': 25, 'additionalDirectories': 20}Vérifier que les répertoires additionnels existent encore, car un chemin mal capturé y reste indéfiniment :
python3 -c "import json, osd = json.load(open(os.path.expanduser('~/.claude/settings.json')))for x in d.get('permissions', {}).get('additionalDirectories', []): if not os.path.isdir(os.path.expanduser(x)): print('inexistant ou malforme :', x)"inexistant ou malforme : /home/bob/Projets/test-astro-5/^\s*inexistant ou malforme : /home/bob/Projets/lab-ansible/labs/000-prepare/{challengeCes deux entrées sont des fragments d'expression régulière et d'accolade capturés comme des chemins. Ils ne servent à rien, mais ils montrent que personne n'a relu le fichier depuis longtemps.
Repartir propre, et ne pas rechuter
Section intitulée « Repartir propre, et ne pas rechuter »La bonne stratégie n'est ni de tout garder ni de tout interdire, mais de remplacer des milliers de règles littérales par quelques dizaines de règles de préfixe. Un fichier de trente règles se relit en une minute, donc il se relit vraiment, et c'est la seule propriété qui compte sur le long terme.
-
Sauvegarder l'existant, pour pouvoir y repêcher une règle oubliée.
Fenêtre de terminal cp ~/.claude/settings.json ~/.claude/settings.json.$(date +%F) -
Extraire les intentions réelles plutôt que de trier à la main. Le regroupement par préfixe montre les commandes qui reviennent vraiment.
Fenêtre de terminal python3 -c "import json, os, refrom collections import Counterd = json.load(open(os.path.expanduser('~/.claude/settings.json')))c = Counter()for r in d['permissions']['allow']:m = re.match(r'^Bash\(([\w.-]+(?: [\w.-]+)?)', r)if m: c[m.group(1)] += 1for k, n in c.most_common(25): print(f'{n:5d} {k}')" -
Réécrire en règles de préfixe, avec la syntaxe
:*qui n'est reconnue qu'en fin de motif.{"permissions": {"allow": ["Bash(git status:*)","Bash(git diff:*)","Bash(kubectl get:*)","Bash(npm run:*)"],"ask": ["Bash(git push:*)"],"deny": ["Bash(sudo:*)", "Read(//**/.env)", "Read(~/.ssh/**)"]}} -
Vérifier que la configuration active est bien celle attendue, avec
/statusdans Claude Code, puis relancer un scan.
L'hygiène qui évite la rechute tient en trois réflexes. Réserver « ne plus demander » aux commandes de lecture dont la forme est stable. Sortir les secrets de la ligne de commande avant de lancer la commande, pas après. Et relire le fichier quand il dépasse une taille où on ne le relit plus, disons une centaine de règles.
Dépannage
Section intitulée « Dépannage »Les symptômes ci-dessous se ressemblent, mais les causes sont indépendantes : un problème de portée (la règle n'est pas là où vous croyez), un problème de syntaxe (la règle ne correspond pas à ce que vous croyez), ou un problème d'accumulation. La colonne du milieu donne la vérification qui tranche.
| Symptôme | Comment trancher | Solution |
|---|---|---|
Une règle deny ne bloque rien | Elle est en correspondance exacte, sans :* | Passer en Bash(commande:*) |
| Le fichier grossit sans qu'on approuve | Les commandes composées écrivent jusqu'à 5 règles | Approuver les commandes une par une |
| Une permission accordée ne survit pas | C'était une modification de fichier | Normal, ces approbations durent la session |
| Une règle s'applique sans être dans le fichier projet | Elle vient du fichier utilisateur | Les permissions fusionnent, vérifier les trois portées |
| Un secret apparaît dans le fichier | grep -nE '://[^/ :]+:[^@/ ]{3,}@' | Révoquer le secret, puis nettoyer |
| Un répertoire additionnel inconnu | Vérifier son existence sur le disque | Fragment mal capturé, à supprimer |
| Le scan signale une clé qui n'en est pas | Lire la ligne pointée | Faux positif fréquent sur les chaînes de test |
À retenir
Section intitulée « À retenir »- Les permissions fusionnent entre portées, elles ne s'écrasent pas : le fichier ne peut que grossir.
- « Ne plus demander » sur une commande Bash écrit une règle permanente dans
.claude/settings.local.jsondu dépôt. - Une commande composée écrit jusqu'à cinq règles d'un seul coup.
- Une approbation de modification de fichier ne dure que la session et n'écrit rien.
- Un secret passé en préfixe de commande finit en clair dans la configuration, et doit être considéré comme compromis.
denyen correspondance exacte ne couvre presque rien : la forme utile estBash(commande:*).- Le fichier local suit le contrôle de confiance comme le projet depuis la version 2.1.207, avec deux exceptions.
- Un auditeur générique rate des secrets réels : gardez une vérification propre, une expression régulière suffit.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous portent sur les points où le comportement observé surprend : une règle qui ne bloque pas, un fichier qui grossit tout seul, une permission qui disparaît. Chaque réponse donne la commande qui permet de vérifier sur votre propre installation.
Le mécanisme
La documentation officielle le formule ainsi : « Permission rules behave differently because they merge across scopes rather than override ». Les règles de permission fusionnent au lieu de s'écraser, contrairement aux autres réglages.Conséquence : rien ne remplace, rien n'expire, rien ne nettoie.L'accélérateur
Une commande composée approuvée en « ne plus demander » écrit une règle par sous-commande, jusqu'à cinq pour une seule approbation.Mesurer la dérive
python3 -c "import json,os; d=json.load(open(os.path.expanduser('~/.claude/settings.json'))); \
p=d.get('permissions',{}); print({k: len(v) for k,v in p.items()})"
{'allow': 1917, 'deny': 10, 'ask': 25, 'additionalDirectories': 20}
Au-delà de quelques centaines de règles, le fichier n'est plus relu, donc plus contrôlé.Cela dépend du type d'outil
| Type | Effet de « ne plus demander » |
|---|---|
| Commande Bash | Permanent, par dépôt et par commande |
| Modification de fichier | Jusqu'à la fin de la session |
| Lecture seule | Sans objet, pas d'approbation demandée |
Où le fichier est écrit
Dans.claude/settings.local.json à la racine du dépôt git, pas dans le répertoire courant. La règle s'applique donc à toutes les sessions du dépôt, y compris depuis un sous-répertoire ou un worktree.Hors dépôt git, ou quand la racine est votre répertoire personnel, la règle est enregistrée dans le répertoire de lancement.Le réflexe utile
Sur un prompt Bash,Ctrl+E affiche une explication de la commande avec une étiquette de risque, sans l'exécuter.La cause habituelle
"deny": ["Bash(bash)"]
Cette règle ne bloque que la commande nue. Elle laisse passer bash script.sh, qui est pourtant l'usage réel.La forme correcte
"deny": [
"Bash(bash:*)",
"Bash(sudo:*)",
"Read(//**/.env)",
"Read(~/.ssh/**)"
]
La syntaxe :* n'est reconnue qu'en fin de motif. Dans Bash(git:* push), le deux-points est traité comme un caractère littéral.Ce qui ne contourne pas un deny
Claude Code retire les wrapperstimeout, time, nice, nohup, stdbuf avant de comparer. Un timeout 30 commande est donc bien soumis aux mêmes règles.L'ordre des opérations compte
- Révoquer le secret, ou changer le mot de passe.
- Nettoyer le fichier ensuite.
Comment il est arrivé là
En approuvant définitivement une commande qui le portait en préfixe :DATABASE_URL=postgresql://app:motdepasse@localhost:5432/app npx prisma migrate dev
La règle enregistrée contient la ligne complète.Le détecter
grep -nE '://[^/ :]+:[^@/ ]{3,}@' ~/.claude/settings.json
L'éviter
Sortir le secret de la ligne de commande avant de la lancer : fichier.env, variable exportée dans le shell, ou gestionnaire de secrets. La commande approuvée ne contient alors qu'un nom de variable.Les trois fichiers
| Fichier | Portée | Versionné |
|---|---|---|
~/.claude/settings.json |
Toutes vos sessions | Non |
.claude/settings.json |
Le dépôt, pour l'équipe | Oui |
.claude/settings.local.json |
Le dépôt, pour vous | Non, gitignoré |
La différence qui compte pour la sécurité
La documentation précise : « Because this file is yours rather than the repository's, its permission allow rules take effect without the workspace trust step that .claude/settings.json allow rules require ».Autrement dit, les règlesallow du fichier local s'appliquent sans l'étape de confiance exigée du fichier de projet.Un piège pratique
Claude Code configure git pour ignorer le fichier local qu'il crée lui-même. Un fichier créé à la main n'hérite pas de cette protection.Le réglage
{
"allowManagedPermissionRulesOnly": true
}
La documentation le décrit ainsi : « Prevent user and project settings from defining allow, ask, or deny permission rules. Only rules in managed settings apply ».Pourquoi c'est la seule réponse fiable en entreprise
Parce que les permissions fusionnent normalement entre les portées. Sans ce verrou, une règle administrée coexiste avec les règles locales au lieu de les remplacer, et la politique centrale ne garantit rien.La contrainte
Le réglage n'est lisible que depuis les réglages administrés, déployés par l'outillage de gestion de parc. Il ne s'active pas depuis un fichier utilisateur.Le principe
Un hookPreToolUse reçoit la commande en JSON et peut la refuser :{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "la commande contient un secret"
}
}
Pourquoi deux détecteurs
Mesure sur gitleaks 8.30.0 : il bloqueghp_, sk_live_, les JWT et les clés génériques, mais laisse passer postgresql://app:motdepasse@db:5432/app. Une expression régulière attrape ce cas :grep -qE '://[^/ :]+:[^@/ ]{3,}@'
Le coût
Le hook tourne avant chaque commande Bash. Sans pré-filtre, le démarrage de gitleaks coûte 344 ms par commande ; en ne le lançant que si la commande porte un indice de secret, on tombe à 8 ms.Sa limite
Il attrape une inattention, pas un attaquant : un secret encodé ou assemblé par concaténation lui échappe.L'outil
npx ecc-agentshield scan
Grade: C (70/100)
Secrets ██████████░░░░░░░░░░ 50
Permissions ░░░░░░░░░░░░░░░░░░░░ 0
Hooks ████████████████████ 100
MCP Servers ████████████████████ 100
Il est solide sur les permissions trop larges, les hooks et les serveurs MCP, dont il vérifie les noms contre des typosquats connus. Son mode d'analyse par modèle est optionnel : sans clé d'API, il refuse de démarrer, donc un scan ordinaire n'envoie rien.Sa limite mesurée
Sur une configuration réelle, il a produit deux constats critiques de clés AWS pointant des chaînes de test, et n'a signalé aucun des deux vrais secrets présents.La vérification à garder
grep -nE '://[^/ :]+:[^@/ ]{3,}@' ~/.claude/settings.json
Une expression régulière suffit là où l'outil générique échoue.