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
Par défaut, le runtime natif exécute les commandes via /bin/sh. Définissez [runtime].shell pour utiliser un shell différent :
[runtime]
shell = "bash" # se résout via PATH, ou utilisez un chemin absolu
Sous Unix, les shells compatibles POSIX sont appelés comme suit : <shell> -c "<command>". powershell/pwsh sélectionnent la syntaxe et la stratégie PowerShell sur chaque hôte de bureau pris en charge et s’exécutent comme <interpreter> -NoProfile -NonInteractive -Command <command>, afin que les scripts de profil ne puissent pas redéfinir des commandes à l’insu de la stratégie et que les invites ne puissent pas bloquer l’exécution. La valeur doit être soit un nom de commande nu trouvé dans PATH (par ex. "bash" ou "pwsh"), soit un chemin absolu vers un exécutable (par ex. "/bin/bash"); les chemins relatifs comportant des séparateurs (par ex. "./sh", "bin/sh") sont rejetés. Elle est validée au démarrage de l’environnement d’exécution : un shell vide, absent, non exécutable ou mal formé échoue donc immédiatement avec une erreur claire au lieu de faire échouer la première commande. La valeur par défaut est "sh" lorsqu’elle n’est pas définie.
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" # ou laisser non défini -> cmd.exe /C "<cmd>" (par défaut)
powershell et pwsh (en tant que noms seuls résolus via PATH, ou en tant que chemin absolu tel que "C:\\Program Files\\PowerShell\\7\\pwsh.exe") sont exécutés via PowerShell ; toute autre valeur (y compris la valeur par défaut sh et la valeur explicite cmd) est exécutée via cmd.exe /C, conformément au comportement historique. Seule une valeur vide ou composée d’espaces est rejetée ; l’interpréteur est recherché 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 fonctionne. 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.
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