Il y a quelques jours, je présentais Greywall — un sandbox kernel-level qui contient pi grâce à une approche deny-by-default. C’est votre mur extérieur. Mais qu’en est-il des menaces à l’intérieur de la frontière ? L’agent qui écrit accidentellement dans le mauvais projet, le fichier .env qui se retrouve dans le contexte LLM, le skill dont le SKILL.md a été silencieusement modifié. C’est un problème différent, qui nécessite un outil différent.

Aujourd’hui je publie pi-secured-setup — une extension pi qui ajoute des Guards, des Scanners et un audit trail directement dans l’agent. Pas de modules kernel, pas de conteneurs, pas de dépendances externes. Un simple pi install et vous êtes protégé.

Modèle de menaces — que protège-t-on concrètement ?

pi-secured-setup n’est pas conçu pour arrêter un attaquant déterminé. C’est le boulot de Greywall. Il cible cinq scénarios réalistes que tout utilisateur de pi rencontrera tôt ou tard :

MenaceExempleSévérité
Dommages accidentels inter-projetswrite vers /home/user/autre-projet/file.tsÉlevée
Exposition de fichiers sensiblesL’agent lit votre .env et son contenu atteint le contexte LLMÉlevée
Commandes destructricesrm -rf /, sudo, git push --forceÉlevée
Chaîne d’approvisionnement (skills)Un SKILL.md de skill est modifié pour injecter des instructions malveillantesMoyenne
Exfiltration de donnéesCommandes curl ou aws envoyant des données à l’extérieurMoyenne
Aucune traçabilitéQuelque chose a planté, mais vous ne savez pas quoiMoyenne

Chacun de ces scénarios m’est arrivé. Le dernier est le plus sournois — sans audit trail, vous ne pouvez même pas diagnostiquer le problème.

Architecture — trois couches, une extension

pi-secured-setup est une seule extension pi avec trois couches distinctes :

Guards — évaluent les appels d’outils avant l’exécution et peuvent les bloquer ou demander confirmation. Ils s’exécutent dans un pipeline fixe avec un handler unique combiné — pas de doubles dialogues, pas de race conditions.

Scanners — observent les données sans bloquer. Ils détectent les secrets dans le payload provider et vérifient l’intégrité des skills. Ils ne bloquent jamais l’exécution d’un outil.

Audit — enregistre tout dans un fichier JSONL en append-only avec rotation automatique.

La décision de conception clé : Guards et Scanners sont séparés par intention. Les Guards peuvent bloquer. Les Scanners peuvent seulement observer et rapporter. Ça signifie que le scanner de secrets ne bloquera jamais accidentellement votre workflow — il rédacte silencieusement et vous notifie a posteriori.

Le pipeline de Guards

Les trois modules Guard (boundary, protected paths, bash gate) sont évalués par un handler tool_call unique dans un ordre fixe :

boundary → protected-paths → bash-gate

Le premier bloc gagne. Si boundary bloque une écriture, protected paths et bash gate ne s’exécutent pas. Si boundary autorise, protected paths prend la main. Si les deux autorisent et que l’outil est bash, la commande est classifiée. Un verdict par appel d’outil, une entrée d’audit.

Guards en action — ce qui est bloqué

Application de la frontière (Boundary)

La frontière est votre répertoire projet (cwd). Les opérations fichiers via read, write et edit sont vérifiées par rapport à cette frontière. Bash est explicitement exclu — on ne peut pas extraire fiablement des chemins d’une commande shell arbitraire.

SituationOutilVerdict
Écriture dans le projetwrite, edit✅ Autorisé
Lecture dans le projetread✅ Autorisé
Écriture hors projetwrite, edit🚫 Bloqué
Lecture hors projetread⚠️ Confirmation
Lecture/écriture sur chemin externe autoriséany✅ Autorisé
Toute commande bashbash✅ Autorisé (géré par bash gate)

La liste allowed-external permet de whitelist des chemins comme ~/.agents/skills ou /tmp qui sont hors projet mais nécessaires au fonctionnement normal.

Chemins protégés (Protected Paths)

Même à l’intérieur de la frontière, certains fichiers méritent une protection supplémentaire. Les chemins protégés utilisent des patterns glob comparés au fichier cible :

.env, .env.*, *.key, *.pem, id_rsa*, *secret*, *credential* ...

Write ou edit vers un chemin protégé → blocage. Read depuis un chemin protégé → confirmation (configurable en allow ou block). Les patterns sont entièrement configurables par projet.

Bash Gate

Chaque commande bash est classifiée dans l’une des quatre catégories selon des règles regex :

CatégorieExemplesVerdict
SAFEls, cat, grep, git status✅ Auto-approuvé
MODERATEnpm install, mkdir, git commit✅ Auto-approuvé (loggé)
DANGEROUSrm -rf, sudo, eval, dd if=⚠️ Confirmation
EXTERNALcurl, ssh, aws, gcloud⚠️ Confirmation
Inconnuetout ce qui ne matche pas⚠️ Confirmation

Les pipes sont gérés correctement : cat file | rm -rf / est classifié DANGEROUS car le pipeline prend le composant le plus dangereux. Les sous-shells comme $(whoami) sont extraits et classifiés indépendamment.

Voici ce que donne le dialogue de confirmation en pratique :

🔒 Bash Command
⚠️ Dangerous command — allow execution?

  rm -rf node_modules

Classification: DANGEROUS

Scanners — secrets et skills

Scanner de secrets

Le scanner de secrets s’exécute sur before_provider_request — il voit le payload exact sur le point d’être envoyé au LLM, avant qu’il ne quitte votre machine. Il parcourt récursivement chaque chaîne de caractères du payload (provider-agnostic — fonctionne avec Anthropic, OpenAI, Google, n’importe quel provider) et la compare à plus de 15 patterns :

  • Clés d’accès AWS (AKIA...), clés secrètes AWS
  • Clés API Anthropic, OpenAI, Gemini
  • En-têtes de clés privées (-----BEGIN RSA PRIVATE KEY-----)
  • Clés API génériques, bearer tokens, mots de passe
  • Chaînes de connexion base de données (postgres://, mongodb://, redis://)
  • Tokens GitHub (ghp_, ghs_), tokens Slack, tokens Discord
  • Détection d’entropie élevée en fallback

Quand un secret est trouvé, il est remplacé par ***REDACTED:{pattern-name}***. L’agent conserve le type de secret sans la valeur, ce qui lui permet de raisonner sur votre configuration.

DATABASE_URL=postgres://user:supersecret@db.example.com:5432/prod

devient :

DATABASE_URL=***REDACTED:db-connection***

Pourquoi scanner uniquement la requête et pas la réponse ? Si les secrets sont rédactés avant d’atteindre le modèle, le modèle ne peut jamais les répéter dans une réponse. La rédaction côté input est suffisante.

La mitigation des faux positifs est intégrée : les placeholders comme YOUR_API_KEY, xxx, REPLACE_... sont ignorés. Les lignes de commentaires (#, //, --) sont ignorées entièrement. Et les en-têtes PEM de clés privées (qui commencent par -----) sont correctement distinguées des commentaires SQL (qui commencent par -- ).

Scanner de skills

Les skills sont puissants — un fichier SKILL.md entre directement dans le contexte LLM. Si quelqu’un modifie le SKILL.md d’un skill, il peut injecter des instructions arbitraires dans votre agent. Le scanner de skills :

  1. Découvre tous les skills dans les répertoires standards (~/.agents/skills/, ~/.pi/agent/skills/, .pi/skills/, .agents/skills/)
  2. Hash chaque SKILL.md en SHA-256
  3. Compare avec skill-approvals.json
  4. Skills nouveaux ou modifiés → prompt d’approbation (une seule fois)
  5. Précédemment non approuvés → notification uniquement (pas de dialogue bloquant)

Seul SKILL.md est hashé — les scripts et assets annexes ne le sont pas. Le bash gate couvre l’exécution des scripts. Ça garde la vérification rapide (un fichier par skill) et concentrée sur la surface d’attaque LLM réelle.

Installation et configuration

Installation en une commande

pi install git:github.com/mwolff44/pi-secured-setup

C’est tout. Au premier lancement, l’extension crée ~/.pi/agent/security/ avec les configs par défaut et scanne vos skills pour approbation.

Première exécution

🔒 Skill Review: grill-me
Skill: grill-me
Source: ~/.agents/skills/
Path: /home/user/.agents/skills/grill-me/SKILL.md

🆕 New skill detected.

--- SKILL.md preview ---
# Grill Me
Interview the user relentlessly about a plan or design...
---

  Approve
> Deny
  Skip

Chaque skill reçoit un seul prompt. Les sessions suivantes affichent uniquement une notification pour les skills non approuvés.

Configuration en trois couches

La configuration est chargée depuis trois couches, fusionnées par ordre de priorité :

1. defaults/              — livré avec le package (ne pas éditer)
2. ~/.pi/agent/security/  — overrides spécifiques à la machine
3. .pi/security/          — overrides spécifiques au projet

Les listes de patterns sont additives. Un préfixe ! exclut un pattern hérité :

// .pi/security/protected-paths.json
{
  "patterns": [
    "!*secret*",        // Retirer le pattern *secret* hérité pour ce projet
    "config/prod.yaml"  // Ajouter un pattern spécifique au projet
  ],
  "readAction": "allow" // Ne pas confirmer les lectures de fichiers protégés dans ce projet
}

Ça signifie que vous pouvez durcir la sécurité par projet sans toucher à votre config globale, ou assouplir des règles spécifiques là où elles n’ont pas de sens.

Exemple par projet

mkdir -p .pi/security
// .pi/security/command-rules.json
{
  "dangerous": [
    "terraform destroy",
    "kubectl delete namespace"
  ]
}
// .pi/security/allowed-external.json
{
  "paths": [
    "../shared-libs"
  ]
}

Le dashboard /security et les commandes

/security — Dashboard

🔒 Security Dashboard — Session m5x8k2-abc123

This session:
  🔴 Blocked:       3 actions
  🟡 Confirmed:     5 actions
  🔵 Auto-approved: 42 actions
  ⚠️  Secrets redacted: 2

Skill status:
  ✅ 18 approved, ⚠️ 0 pending, 🚫 0 denied

Recent events:
  10:28 [BLOCKED] write → /home/user/other-project/file.ts (outside boundary)
  10:25 [CONFIRMED] bash → curl https://api.example.com (external)
  10:22 [REDACTED] secret (anthropic-key) in read → .env

Log file: ~/.pi/agent/security/audit.jsonl

Référence complète des commandes

CommandeDescription
/securityDashboard avec compteurs, événements récents, statut des skills
/security:skillsRe-déclencher le flux d’approbation pour tous les skills
/security:trust <name>Approuver un skill par nom, persister dans la config
/security:allow <path>Ajouter un chemin externe à la liste autorisée
/security:clean [jours]Élaguer les entrées d’audit plus anciennes que N jours (défaut : 30)

Audit log

Chaque action est enregistrée en JSONL dans ~/.pi/agent/security/audit.jsonl :

{
  "timestamp": "2026-05-07T10:28:15.123Z",
  "sessionId": "m5x8k2-abc123",
  "type": "boundary.block",
  "severity": "warning",
  "details": {
    "tool": "write",
    "path": "/home/user/autre-projet/file.ts",
    "boundary": "/home/user/mon-projet",
    "reason": "write outside project boundary"
  }
}

Le log rotate automatiquement — par défaut 10MB par fichier, 3 fichiers conservés. Configurable via ~/.pi/agent/security/audit-config.json.

Greywall + pi-secured-setup : défense en profondeur

Ces deux outils résolvent des problèmes différents. Ils se complètent.

PréoccupationGreywallpi-secured-setup
Containment kernel-level
Application de frontière fichier
Rédaction de secrets dans le contexte LLM❌ (filtre les destinations, pas le contenu)
Classification de commandes✅ (niveau syscall kernel)✅ (patterns regex, dialogues utilisateur)
Vérification d’intégrité des skills
Audit trail❌ (logs de violations)✅ (JSONL, dashboard, rotation)
Matching glob de chemins protégés
Filtrage réseau✅ (proxy SOCKS5)
Substitution de credentials✅ (proxy HTTP)❌ (rédacte dans le payload)
Nécessite modules kernel / root
Fonctionne sur tout OS❌ (spécifique Linux/macOS)✅ (tourne dans pi, cross-platform)

Setup recommandé : Greywall pour le mur extérieur — containment kernel-level, filtrage réseau, protection des credentials. pi-secured-setup pour le mur intérieur — guards applicatifs, rédaction de secrets, vérification des skills, audit trail. Ensemble, ils fournissent une défense en profondeur significative sans point de défaillance unique.

Conclusion

La sécurité, c’est des couches, pas des silver bullets. Greywall contient pi au niveau kernel. pi-secured-setup ajoute de la conscience à l’intérieur de l’agent lui-même — bloquant les dommages accidentels, rédactant les secrets avant qu’ils n’atteignent le LLM, vérifiant l’intégrité des skills, et conservant un audit trail complet.

L’extension est open source, testée (98 tests unitaires), et installable en une seule commande. Chaque guard est une fonction pure sans dépendance pi, ce qui rend la logique principale indépendamment testable et auditable.

Si vous utilisez pi au quotidien — surtout avec accès à des projets sensibles — je dirais que ce n’est pas optionnel. C’est le minimum vital de sécurité.

pi install git:github.com/mwolff44/pi-secured-setup

Les sources sont sur GitHub. Contributions, retours et bug reports sont les bienvenus.

Quelles sont vos préoccupations de sécurité avec les agents de code IA ? Y a-t-il des menaces que je n’ai pas couvertes ici ? Dites-le-moi en commentaire !