feat(secu): confirmation liée (tool+args) pour les actions irréversibles — anti ride-the-oui #28

Merged
kevin merged 1 commit from secu/risky-confirm-p2 into main 2026-07-20 16:08:15 +00:00
Owner

Résurrection du draft #137 (anti « ride-the-oui »), réimplémenté post-P2

La branche originale secu/risky-confirm-binding (24-06) datait d'avant le refactor P2 (wolf_tools 5235→595 l.) — rebase impossible, réimplémentation sur le registre ToolDef.

Ce que ça ferme

En mode Demande, un « oui » de l'utilisateur flottait : donné pour une action A, il autorisait n'importe quelle action B ré-émise ensuite (détournement par prompt injection — outil différent OU mêmes outil/args détournés). Désormais un outil risqué (irréversible/sortant) exige un pending qui matche exactement tool_name ET args, plus une confirmation courte (« oui ») ou une approbation UI. Purge des autres pendings exec: : un « oui » ne peut viser qu'une seule action.

Architecture

  • ToolDef.risky : nouveau flag source-unique (comme read_only/admin_only), posé sur 10 outils cœur.
  • RISKY_TOOLS (façade wolf_tools) : dérivé du registre + channel_send/webhook_send (outils sortants auto-découverts des plugins, alignés sur _CATASTROPHIC_OUTWARD_PREFIXES de trust_gate) + heuristique verbes mutants pour les MCP dynamiques (mcp_gmail_send…).
  • Mode Restreint : l'approbation par carte UI devient liée aux args (autoriser A ne débloque pas un B ré-émis avec d'autres arguments).

Écart assumé vs le draft

Le draft gatait TOUS les modes, y compris l'Autonome. Ici le gate est scopé au mode Demande (+ liaison args de la carte Restreint) : l'Autonome reste non bridé, conformément au modèle de menace (mono-user/VPS, agent root voulu) et à la règle « ne PAS brider l'agent auto-améliorable ». La réponse injection en Autonome reste le trust-tainting (Lot E).

Tests

13 tests de logique pure (test_risky_confirmation.py) : flag registre, heuristique MCP, confirmation courte stricte, matching lié (4 scénarios de détournement).

Suite complète locale : 888 passed, mêmes 9 échecs + 2 erreurs préexistants que main (tests Postgres-dépendants, verts en CI).

🤖 Generated with Claude Code

https://claude.ai/code/session_01F5SST5qru4jYV2NoCwPBu6

## Résurrection du draft #137 (anti « ride-the-oui »), réimplémenté post-P2 La branche originale `secu/risky-confirm-binding` (24-06) datait d'avant le refactor P2 (wolf_tools 5235→595 l.) — rebase impossible, réimplémentation sur le registre `ToolDef`. ### Ce que ça ferme En mode **Demande**, un « oui » de l'utilisateur flottait : donné pour une action A, il autorisait n'importe quelle action B ré-émise ensuite (détournement par prompt injection — outil différent OU mêmes outil/args détournés). Désormais un outil **risqué** (irréversible/sortant) exige un pending qui matche **exactement** `tool_name` ET `args`, plus une confirmation courte (« oui ») ou une approbation UI. Purge des autres pendings `exec:` : un « oui » ne peut viser qu'une seule action. ### Architecture - **`ToolDef.risky`** : nouveau flag source-unique (comme `read_only`/`admin_only`), posé sur 10 outils cœur. - **`RISKY_TOOLS`** (façade wolf_tools) : dérivé du registre + `channel_send`/`webhook_send` (outils sortants auto-découverts des plugins, alignés sur `_CATASTROPHIC_OUTWARD_PREFIXES` de trust_gate) + heuristique verbes mutants pour les MCP dynamiques (`mcp_gmail_send`…). - **Mode Restreint** : l'approbation par carte UI devient liée aux args (autoriser A ne débloque pas un B ré-émis avec d'autres arguments). ### Écart assumé vs le draft Le draft gatait TOUS les modes, y compris l'Autonome. Ici le gate est **scopé au mode Demande** (+ liaison args de la carte Restreint) : l'Autonome reste non bridé, conformément au modèle de menace (mono-user/VPS, agent root voulu) et à la règle « ne PAS brider l'agent auto-améliorable ». La réponse injection en Autonome reste le trust-tainting (Lot E). ### Tests 13 tests de logique pure (`test_risky_confirmation.py`) : flag registre, heuristique MCP, confirmation courte stricte, matching lié (4 scénarios de détournement). Suite complète locale : 888 passed, mêmes 9 échecs + 2 erreurs préexistants que main (tests Postgres-dépendants, verts en CI). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01F5SST5qru4jYV2NoCwPBu6
feat(secu): confirmation liée (tool+args) pour les actions irréversibles — anti ride-the-oui
All checks were successful
CI / Backend — pytest (pull_request) Successful in 45s
CI / i18n — usage → locales (pull_request) Successful in 5s
3b8a863a70
Ressuscite le draft #137 (branche secu/risky-confirm-binding, jamais mergée),
réimplémenté sur l'archi post-P2 :

- ToolDef gagne un flag `risky` (source unique, comme read_only/admin_only) ;
  posé sur 10 outils cœur (bash_exec, file_write, file_patch, service_call,
  provider_manage, mcp_manage, channel_manage, voice_manage, subagent_delete,
  conversations_manage).
- Façade wolf_tools : RISKY_TOOLS dérivé du registre + channel_send/
  webhook_send (sortants auto-découverts, alignés trust_gate) +
  heuristique verbes mutants pour les outils MCP dynamiques.
- chat.py mode Demande : un outil risqué exige un pending qui matche
  EXACTEMENT (tool_name ET args) l'action proposée au tour précédent +
  confirmation courte (« oui ») ou approbation UI. Un « oui » donné pour A
  n'autorise plus un B glissé par injection ; purge des autres pendings
  exec: (un seul « oui » ciblable à la fois).
- Mode Restreint : l'approbation par carte UI devient liée aux args.
- Écart assumé vs draft : gate scopé au mode Demande (+ carte Restreint
  liée) — l'Autonome reste non bridé, conformément au modèle de menace
  mono-user et à « ne pas brider l'agent ».
- 13 tests (logique pure, sans boot FastAPI).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F5SST5qru4jYV2NoCwPBu6
kevin merged commit 5402da2870 into main 2026-07-20 16:08:15 +00:00
kevin deleted branch secu/risky-confirm-p2 2026-07-20 16:08:16 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kevin/Gungnir!28
No description provided.