Isolation
Le runtime peut encapsuler les invocations d’outils dans un bac à sable au niveau de l’OS qui restreint l’accès au système de fichiers à l’espace de travail et supprime l’accès aux secrets du processus parent. Ceci est distinct du système d’autonomie et de la liste d’autorisation des commandes : ce sont des couches de politique qui décident si un outil peut s’exécuter ; le bac à sable est une couche de mécanisme qui confine ce qu’un outil en cours d’exécution peut atteindre s’il s’exécute.
Les paramètres du bac à sable se trouvent dans un profil de risque. Chaque agent pointe vers un profil de risque via agents.<alias>.risk_profile ; les options enable/backend du bac à sable de l’agent sont lues depuis ce profil.
Fournisseurs de modèles CLI (par exemple grok_cli) : la CLI externe se trouve en dehors du processus natif d’approbation des outils de ZeroClaw. Le bac à sable du profil de risque mentionné ci-dessus ne l’isole pas. Le fournisseur ACP grok_cli injecte donc par défaut --sandbox strict, --permission-mode dontAsk et un ensemble d’outils intégrés vide, et rejette les demandes d’autorisation ACP (en sélectionnant reject_once lorsque la CLI le propose, et en annulant sinon). Les indicateurs de contournement explicites dans l’alias extra_args sélectionnent plutôt l’option allow_once de la demande ; cela ne désactive pas le bac à sable actif du système d’exploitation de Grok et ne passe pas outre ses règles de refus. Les autres modes d’autorisation restent fermés en cas d’échec. Voir Catalogue → Grok Build CLI.
sandbox_enabled = false (ou sandbox_backend = "none") désactive l’enveloppe de sandbox supplémentaire au niveau du système d’exploitation du profil. Avec le runtime natif, les outils se retrouvent sans sandbox au niveau du système d’exploitation. Avec [runtime] kind = "docker", le runtime Docker reste la limite du conteneur et est signalé comme docker-runtime ; ces paramètres empêchent un second conteneur de sandbox d’envelopper le propre docker run du runtime. Consultez l’exemple minimal fonctionnel canonique pour voir comment un profil de risque s’intègre au reste de la configuration.
Détection automatique
sandbox_backend = "auto" sélectionne le meilleur backend disponible au démarrage :
| Plateforme | Ordre préféré |
|---|---|
| Linux | Landlock (noyau 5.13+) → Bubblewrap → Firejail → Docker → aucun |
| macOS | Seatbelt (sandbox-exec, natif) → Docker → aucun |
| Windows | AppContainer (expérimental) → Docker → aucun |
| Aucun | Docker (si le daemon est accessible) → aucun |
Pour forcer un backend spécifique, définissez sandbox_backend sur l’une des valeurs littérales listées ci-dessus.
Ce que le bac à sable confine
Accès aux fichiers
- Accès en lecture : restreint à l’espace de travail,
/usr,/lib,/etc(lecture seule) et aux chemins supplémentaires explicitement listés. - Accès en écriture : restreint à l’espace de travail et à
/tmp. - Chemins interdits : règles de préfixe de composant absolu de
[risk_profiles.<alias>].forbidden_paths. Les préfixes d’autorisation et de refus concurrents appliquent une priorité à la correspondance la plus spécifique, le refus l’emportant en cas d’égalité ; voir Règles de chemin d’autonomie.
Réseau
Par défaut, les outils en bac à sable disposent d’un accès réseau sortant complet mais ne peuvent pas écouter en entrée. Réserves propres à chaque backend :
- Landlock ne contrôle pas le réseau, il s’applique uniquement au système de fichiers.
- Bubblewrap et Firejail peuvent bloquer le réseau lorsqu’ils sont configurés.
- Le mode réseau du conteneur Docker suit
[runtime.docker].networklorsque[runtime].kind = "docker".
Les contrôles réseau spécifiques à chaque outil (browser, HTTP, web_fetch) se trouvent dans les blocs de configuration propres à ces outils ([browser].allowed_domains, [http_request].allowed_domains, [web_fetch].allowed_domains).
Pour http_request, les cibles privées/locales restent bloquées par défaut. Utilisez [http_request].allowed_private_hosts pour n’autoriser que des hôtes privés/locaux nommés tels que localhost ou 10.0.0.1 tout en conservant [http_request].allowed_domains non vide ; allowed_domains = [] désactive toujours les requêtes. Le paramètre existant [http_request].allow_private_hosts = true reste une option d’activation de compatibilité plus large.
Environnement
Le bac à sable ne transmet que les variables d’environnement listées dans [risk_profiles.<alias>].shell_env_passthrough. Les secrets hérités n’atteignent pas les outils en bac à sable sauf s’ils sont explicitement transmis.
Limites de processus
Les délais d’expiration par outil (wall-time) sont définis dans le bloc de configuration propre à l’outil ([shell_tool].timeout_secs, etc.). Les limites spécifiques à Docker (mémoire, CPU) sont définies dans [runtime.docker] lorsque le type de runtime de l’agent est défini sur docker :
Binaire du shell
Lorsque [runtime].shell n’est pas défini, le runtime natif détecte une valeur par défaut selon la plateforme. Sous Windows, il essaie pwsh, puis powershell, puis cmd.exe. Sous macOS, il utilise d’abord le shell de connexion passwd de l’utilisateur courant, puis essaie zsh, bash et /bin/sh. Sous Linux, il utilise d’abord le shell de connexion passwd, puis essaie bash, zsh et /bin/sh. Sous Android, la valeur reste fixée à /system/bin/sh. Définissez [runtime].shell pour choisir explicitement un interpréteur :
[runtime]
shell = "bash" # se résout via PATH, ou utilisez un chemin absolu
Sous Unix, les shells compatibles POSIX sont appelés avec <shell> -c "<command>". powershell/pwsh sélectionnent la syntaxe et la politique PowerShell sur chaque hôte de bureau pris en charge et s’exécutent avec <interpreter> -NoProfile -NonInteractive -Command <command>, de sorte que les scripts de profil ne peuvent pas redéfinir des commandes en contournant la politique et que les invites ne peuvent pas bloquer l’exécution. La valeur doit être soit un simple nom de commande présent dans PATH (par ex. "bash" ou "pwsh"), soit un chemin absolu vers un exécutable (par ex. "/bin/bash") ; la validation de la configuration rejette les valeurs vides et les chemins relatifs contenant des séparateurs (par ex. "./sh", "bin/sh"). Avant le lancement, ZeroClaw canonicalise directement un chemin de shell absolu et résout un nom simple à partir du PATH effectif lorsqu’il est fourni ; une fabrique d’exécution peut résoudre et conserver ce lanceur canonique plus tôt, tandis que les autres chemins utilisent la résolution conservée ou celle de l’environnement lors de la préparation de la commande. La cible doit être un fichier exécutable ordinaire, et tout échec est renvoyé lors de la construction de l’exécution ou de la préparation de la commande, avant toute exécution. La configuration explicite prime sur la détection par défaut. La recherche du shell de connexion Unix utilise getpwuid_r ; en cas d’échec ou si elle désigne un exécutable indisponible, l’ordre de repli propre à la plateforme est utilisé. Si un PATH injecté omet un nom simple par défaut sélectionné, la préparation échoue au lieu de changer d’interpréteur.
Firejail, Bubblewrap et Seatbelt de macOS remplacent la commande hôte par un lanceur de bac à sable. Lorsque l’identité de shell demandée diffère du chemin exécutable canonique, le wrapper doit préserver cette identité (par exemple, sh sélectionnant un applet BusyBox ou un mode de compatibilité Bash) tout en exécutant la cible canonique validée. Sous Linux, Firejail et Bubblewrap nécessitent un env ou genv compatible GNU prenant en charge --argv0 dans les entrées absolues de PATH du processus hôte. ZeroClaw sonde chaque candidat pendant deux secondes au maximum ; l’assistant et ses bibliothèques doivent être accessibles à l’intérieur du bac à sable. Sur macOS, Seatbelt utilise le /bin/bash du système avec un trampoline exec -a fixe, de sorte qu’une installation séparée de GNU coreutils n’est pas requise. Le trampoline transmet l’identité demandée et les arguments de commande comme arguments de processus, et non sous forme de code shell interpolé. ZeroClaw n’élargit pas l’accès au système de fichiers et ne revient pas à une commande non sandboxée lorsqu’un assistant requis ne peut pas être exécuté. La recherche de l’assistant hôte sous Linux n’utilise pas la surcouche d’environnement réservée à la TUI.
Pour ces lancements enveloppés préservant l’identité, les chemins de shell canoniques contenant = restent rejetés ; sous Linux, env interpréterait de tels opérandes comme des affectations de variables d’environnement. Les chemins d’assistants Linux contenant = sont rejetés pour la même raison, et un assistant manquant ou non pris en charge produit une erreur de préparation. L’exécution native directe, Landlock et la sélection séparée du shell dans le conteneur Docker ne nécessitent pas d’assistant d’identité sur l’hôte.
Sous Windows, la valeur sélectionne la famille d’interpréteurs d’après le nom de son fichier :
[runtime]
shell = "pwsh" # PowerShell 7+ -> pwsh -NoProfile -NonInteractive -Command <cmd>
# shell = "powershell" # Windows PowerShell 5.x
# shell = "cmd" # cmd.exe /C "<cmd>" explicite
powershell et pwsh (sous forme de nom simple résolu via PATH, ou de chemin absolu tel que "C:\\Program Files\\PowerShell\\7\\pwsh.exe") s’exécutent via PowerShell ; toute autre valeur explicite s’exécute via cmd.exe /C, conformément au comportement historique. Seule une valeur vide ou composée uniquement d’espaces est rejetée sous Windows ; l’interpréteur est localisé au moment du lancement.
L’outil shell, les outils de compétences basés sur le shell et les tâches shell exécutées par cron ou par le planificateur utilisent tous cette sélection de l’environnement d’exécution. L’environnement d’exécution indique également le dialecte du shell à la politique de sécurité, afin que celle-ci valide le même langage que celui qui sera utilisé pour exécuter la commande.
La même sélection d’environnement d’exécution est communiquée au modèle. La ligne ## Runtime de l’invite système contient un champ Shell: qui nomme l’interpréteur configuré (bash, zsh, pwsh, powershell, cmd) et, lorsqu’un outil enregistré accepte une commande rédigée par le modèle (shell, cron_add, cron_update, schedule), une section ## Shell répertorie les formes de commande acceptées par ce dialecte, afin que le modèle écrive Get-ChildItem sous PowerShell et dir /a sous cmd.exe au lieu de deviner à partir du nom du système d’exploitation. Les deux proviennent du même adaptateur qui construit la commande, de sorte que le shell indiqué ne puisse pas diverger de celui qui est exécuté. Les environnements d’exécution sans accès au shell (tels que WASM) omettent les deux. Les recommandations de suppression dans la section de sécurité suivent également le dialecte : trash n’est suggéré que là où il existe.
La stratégie PowerShell accepte une grammaire limitée : des appels de commandes simples, des arguments simples ou entre guillemets, et des pipelines. Les simples lectures de variables telles que $PSHOME et $PSVersionTable.PSVersion sont limitées à une commande Write-Output/echo autonome afin qu’elles ne puissent pas dissimuler des chemins du système de fichiers aux commandes ultérieures. Les expressions et les autres formes d’invocation, notamment les sous-expressions, les parenthèses, les blocs de script, les littéraux de type et les appels de méthodes statiques, les opérateurs d’appel, la redirection, les séparateurs d’instructions, les échappements par accent grave, les variables à portée telles que $env:NAME, les chemins de fournisseurs PowerShell, l’exécution directe de scripts et les interpréteurs de commandes imbriqués, sont classés comme présentant un risque élevé. Les noms de commandes propres à PowerShell ne sont pas ajoutés à la liste d’autorisation par défaut inter-dialectes ; ajoutez les cmdlets dont vous avez besoin à allowed_commands, ou activez "*" avec les paramètres d’approbation et de risque élevé correspondants. Les cmdlets de mutation connues sont soumises aux seuils d’approbation pour les risques moyen et élevé ; les commandes nues inconnues et les cmdlets Verb-Noun présentent par défaut un risque élevé.
Les tâches shell Cron héritent du périmètre d’exécution global lors de la validation comme de l’exécution. Les tâches natives utilisent le shell natif configuré, tandis que les tâches Docker s’exécutent avec l’image, le montage, le réseau, le processeur, la mémoire et les paramètres de racine en lecture seule configurés. Une entrée Cron stocke la commande, et non un environnement d’exécution ou un dialecte copié. Ainsi, après qu’un rechargement du daemon a recréé l’ordonnanceur et le registre d’outils, les tâches existantes utilisent la configuration [runtime] nouvellement chargée lors de leur prochaine exécution. Les exécutions Cron planifiées sont revalidées et ne sont jamais préapprouvées.
Ne s’applique qu’au type d’exécution natif. Docker utilise le shell de son conteneur, et Android (toujours /system/bin/sh) ignore ce paramètre et ne le valide pas.
Notes par backend
Landlock
Le chemin natif Linux. Zéro configuration, imposé par le noyau, très faible surcharge. Nécessite le noyau 5.13+.
Limitations :
- Pas de confinement réseau : Landlock contrôle uniquement l’accès au système de fichiers.
forbidden_pathsest appliqué via des règles basées sur les chemins, et non sur les inodes, de sorte qu’un lien symbolique astucieux peut parfois s’en échapper (nous résolvons les liens avant de les transmettre à Landlock pour atténuer ce problème).
Bubblewrap (bwrap)
Bac à sable basé sur les espaces de noms utilisateur de Flatpak. Confine le système de fichiers et peut bloquer le réseau. Nécessite l’installation de bubblewrap.
Debian/Ubuntu
sudo apt install bubblewrap
Arch
sudo pacman -S bubblewrap
Fedora
sudo dnf install bubblewrap
Firejail
Sandbox basé sur SUID. Plus ancien mais largement disponible.
sh
sudo apt install firejail
Le profil par défaut de Firejail est assez permissif ; ZeroClaw applique un profil personnalisé. Passez des arguments supplémentaires avec firejail_args sur le profil de risque.
Docker
Fonctionne partout où Docker est disponible. Le type de runtime Docker ([runtime] kind = "docker") exécute chaque invocation de shell dans un conteneur éphémère ; consultez le bloc [runtime.docker] ci-dessus pour les contrôles d’image et de ressources. git_operations ne s’exécute pas dans ce conteneur : les commandes Git classées comme écriture sont rejetées pour le runtime Docker, tandis que les commandes classées comme lecture conservent leur isolation de lecture existante côté hôte. Utilisez l’outil shell pour les commandes Git qui doivent s’exécuter dans le conteneur.
sh
docker build -t zeroclaw-sandbox:local dev/sandbox/ # créer l'image de la boîte à outils groupée
Points forts : isolation robuste, fonctionne sur n’importe quel système d’exploitation. Points faibles : coût de démarrage du conteneur à chaque invocation (100–500 ms). Idéal pour les déploiements en production où cette surcharge est acceptable.
Ceinture de sécurité (macOS)
Sandbox macOS natif (sandbox-exec). Les profils sont au format SBPL : ZeroClaw en intègre un pour les exécutions d’outils. Fonctionne sur macOS 10.11+.
Limitation : certains outils CLI (anciennes versions de git, certains binaires liés via Homebrew) ne coopèrent pas avec les règles d’accès aux fichiers de Seatbelt. Si vous voyez des erreurs « Operation not permitted » lors des appels shell de l’agent sur macOS, l’outil a besoin d’un accès plus large au système de fichiers : envisagez de passer à Docker.
none
Aucun sandboxing. Les outils s’exécutent avec tous les privilèges de l’utilisateur du service ZeroClaw. C’est ce que le mode YOLO permet. Bruyant, évident, intentionnel.
Dépannage
- « Sandbox backend unavailable » au démarrage : vérifiez
zeroclaw service statuset le journal ; la détection automatique consigne les backends qu’elle a essayés. - Les outils fonctionnent en développement, mais échouent en service : l’utilisateur du service diffère souvent de l’utilisateur de la CLI. Vérifiez que les deux disposent des permissions liées au sandbox nécessaires (Landlock : aucune ; Bubblewrap : userns activé ; Docker : utilisateur du service dans le groupe
docker). - Invocations d’outils lentes sur le runtime Docker : la première invocation télécharge l’image, les suivantes sont rapides. Pré-téléchargez avec
docker pull <image>.
Référence du code
- Détection :
crates/zeroclaw-runtime/src/security/detect.rs - Backends :
crates/zeroclaw-runtime/src/security/sandbox/(un fichier par backend) - Schéma :
RiskProfileConfigetDockerRuntimeConfigdanscrates/zeroclaw-config/src/schema.rs