# Sécurité CHLOVA > Non négociable. **Risque n°1 : la prompt injection.** L'agent a un accès > quasi-root via Portainer — le modèle de menace part du principe qu'une entrée > hostile peut détourner l'agent. ## Modèle de menace - **Prompt injection** : une donnée lue (message, contenu de workflow, log) tente de faire exécuter à l'agent une action non voulue. - **Exfiltration de secrets** : l'agent ne doit jamais voir de secret en clair. - **Escalade** : reclasser un asset privilégié en réversible pour contourner la review. Interdit par construction (voir `risk-tiers.md`). - **Exposition réseau** : une brique interne deviendrait joignable de l'extérieur. ## Défenses (par couche) ### 1. Réduction de la surface - **Seul le backend CHLOVA est exposé** (auth + TLS). Ollama, n8n, Portainer et les serveurs MCP n'écoutent **que** sur `chlova-internal`. Voir `infra/networks.md`. - Phase 1 : surface Telegram en **long-polling** → **aucun port publié**. ### 2. Accès Docker via socket-proxy (obligatoire) - Jamais de `/var/run/docker.sock` monté dans l'agent ou le MCP Portainer. - `tecnativa/docker-socket-proxy` filtre les endpoints Docker autorisés. - Phase 1 (lecture seule) : n'autoriser que les endpoints de **lecture** (`CONTAINERS=1`, `IMAGES=1`, `NETWORKS=1`, `VOLUMES=1`, `INFO=1`, `VERSION=1`) et **interdire** tout le reste (`POST=0`, `EXEC=0`, `CONTAINERS_CREATE` absent…). Détail dans `infra/socket-proxy/README.md`. ### 3. Scoping des tokens - Token **n8n** : portée minimale (lecture en P1). - Token **Portainer** : portée minimale + `PORTAINER_READ_ONLY=true` en P1 (le serveur MCP annote `readOnlyHint` et **réécrit les secrets en `[REDACTED]`** avant qu'ils n'atteignent le modèle). - Un token = un usage. Rotation documentée. ### 4. Egress filtré - Sortie réseau **par défaut refusée** pour les conteneurs de l'agent. - **Seule exception** : `ollama.com` (proxy cloud Ollama). À appliquer au niveau pare-feu hôte / réseau Docker. Voir `infra/networks.md`. ### 5. Secrets par référence - Tous les secrets (dont `OLLAMA_API_KEY`) via variables d'env / coffre, **jamais en dur**. `.env` n'est jamais commité (`.env.example` fait foi des clés requises). - L'agent manipule des **références**, pas des valeurs. `config.ts` **plante au boot** (fail-closed) si un secret requis manque. ### 6. Lecture seule renforcée (Phase 1) - Le **readonly-filter** de l'orchestrateur n'expose au LLM que les outils MCP `readOnlyHint=true`. Les outils mutants ne sont pas branchés. Double barrière avec le `PORTAINER_READ_ONLY=true` côté serveur MCP. ### 7. Audit - **Toute opération mutante est audit-loggée** (qui/quoi/quand/résultat). En P1, toute exécution d'outil est tracée même si read-only. - Déploiements de stacks en **GitOps** dès que possible (rollback + audit gratuits). ## Surface exposée API/UI (Phase 4) - **Seul le backend** est exposé, via **Traefik + TLS** (label compose, réseau `traefik-public`). Ollama, MCP, n8n, Portainer restent internes. - **Login fort obligatoire** : mot de passe (scrypt) **+ TOTP 2FA** → **JWT** court (HS256). `/api/auth/login` est **rate-limité** (anti brute-force) ; tout le reste exige un Bearer valide. - L'API/UI ne s'**active que si l'auth est configurée** (`apiAuth()` : 4 secrets présents). Sinon, surface Telegram seule (fail-safe). - Secrets d'auth via env (`provision-auth` les génère) ; **jamais commités**, masqués dans les logs (`redactedConfig`). - CORS restreint à `CHLOVA_WEB_ORIGIN` (dev) ; en prod le SPA est servi en same-origin par le backend (Phase 4 frontend). - La capacité d'écriture reste derrière le gatekeeper (Phase 2) quelle que soit la surface : l'API n'élève aucun privilège. ## Invariants vérifiés par test - Aucun outil non-read-only n'est exposé en Phase 1 (`readonly-filter.test.ts`). - Un asset `privileged` ne peut pas être reclassé `reversible` (`gatekeeper.test.ts`). - `config.ts` refuse de démarrer si un secret requis manque. ## Checklist de revue avant tout passage en Phase 2 (écriture) - [ ] socket-proxy en place, endpoints d'écriture toujours refusés tant que non requis - [ ] gatekeeper câblé (vérif statut avant exécution) - [ ] egress toujours limité à `ollama.com` - [ ] audit log couvre toute opération mutante - [ ] tokens re-scopés au strict besoin de la capacité ajoutée