@aimarket/warden 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/README-es.md +20 -13
  3. package/README-fr.md +20 -13
  4. package/README-ru.md +20 -13
  5. package/README-zh.md +20 -13
  6. package/README.md +20 -13
  7. package/dist/claude-hook.d.ts +4 -0
  8. package/dist/claude-hook.d.ts.map +1 -1
  9. package/dist/claude-hook.js +42 -18
  10. package/dist/claude-hook.js.map +1 -1
  11. package/dist/declare.d.ts +80 -0
  12. package/dist/declare.d.ts.map +1 -0
  13. package/dist/declare.js +449 -0
  14. package/dist/declare.js.map +1 -0
  15. package/dist/flow-guard.d.ts +133 -0
  16. package/dist/flow-guard.d.ts.map +1 -0
  17. package/dist/flow-guard.js +1062 -0
  18. package/dist/flow-guard.js.map +1 -0
  19. package/dist/histor.d.ts +3 -0
  20. package/dist/histor.d.ts.map +1 -1
  21. package/dist/histor.js.map +1 -1
  22. package/dist/mcp-server.js +6 -0
  23. package/dist/mcp-server.js.map +1 -1
  24. package/dist/mcp-tools.d.ts.map +1 -1
  25. package/dist/mcp-tools.js +95 -25
  26. package/dist/mcp-tools.js.map +1 -1
  27. package/dist/scan.d.ts +2 -0
  28. package/dist/scan.d.ts.map +1 -1
  29. package/dist/scan.js +7 -2
  30. package/dist/scan.js.map +1 -1
  31. package/dist/static-scan.d.ts +1 -1
  32. package/dist/static-scan.d.ts.map +1 -1
  33. package/dist/static-scan.js +78 -2
  34. package/dist/static-scan.js.map +1 -1
  35. package/dist/wrap-cli.d.ts +3 -0
  36. package/dist/wrap-cli.d.ts.map +1 -1
  37. package/dist/wrap-cli.js +8 -2
  38. package/dist/wrap-cli.js.map +1 -1
  39. package/dist/wrap.d.ts.map +1 -1
  40. package/dist/wrap.js +28 -1
  41. package/dist/wrap.js.map +1 -1
  42. package/docs/flow-guard.es.md +214 -0
  43. package/docs/flow-guard.fr.md +220 -0
  44. package/docs/flow-guard.md +224 -0
  45. package/docs/flow-guard.ru.md +210 -0
  46. package/docs/flow-guard.zh.md +159 -0
  47. package/docs/gates.es.md +27 -3
  48. package/docs/gates.fr.md +28 -2
  49. package/docs/gates.md +26 -3
  50. package/docs/gates.ru.md +26 -3
  51. package/docs/gates.zh.md +15 -2
  52. package/docs/scan.es.md +46 -28
  53. package/docs/scan.fr.md +46 -28
  54. package/docs/scan.md +46 -28
  55. package/docs/scan.ru.md +46 -28
  56. package/docs/scan.zh.md +46 -28
  57. package/docs/scanner-comparison.es.md +289 -174
  58. package/docs/scanner-comparison.fr.md +292 -178
  59. package/docs/scanner-comparison.md +234 -140
  60. package/docs/scanner-comparison.ru.md +279 -165
  61. package/docs/scanner-comparison.zh.md +237 -90
  62. package/package.json +4 -3
package/docs/gates.ru.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > 🌐 [English](gates.md) · **Русский** · [Español](gates.es.md) · [Français](gates.fr.md) · [中文](gates.zh.md)
4
4
 
5
+ **Ruleset v14 (не выпущен, исправление аудита):** `keyStaysLocal` больше не принимает хранение на сервере за сохранение ключа у пользователя. Числа корпуса/MCPTox для v13 ниже исторические; для v14 выполнены только локальные регрессионные тесты, новых прогонов нет.
6
+
5
7
  > [Изменения безопасности 0.7.0 и миграция](security-hardening.ru.md).
6
8
 
7
9
  `Warden.vet(server, tools)` прогоняет упорядоченную цепочку и возвращает один вердикт. Эта страница —
@@ -52,8 +54,8 @@ Severity отвечает на вопрос *сколько внимания э
52
54
 
53
55
  Локальное regex-сканирование всех полей, которые объявляет инструмент: `name`, `description` и
54
56
  `inputSchema`, а начиная с v6 ещё `title`, `outputSchema`, `annotations` и метаданные расширений (всё
55
- остальное, что прислал сервер, кроме иконки-изображения в base64). 35 правил в наборе **v10**: 24
56
- `block`, 11 `advise`, и у 24 из них есть контекстный **guard** — именованная проверка, решающая,
57
+ остальное, что прислал сервер, кроме иконки-изображения в base64). 36 правил в наборе **v14**: 25
58
+ `block`, 11 `advise`, и у 25 из них есть контекстный **guard** — именованная проверка, решающая,
57
59
  действительно ли совпадение — то, что правило ищет. См.
58
60
  [полевой обзор](mcp-survey.ru.md) — прогон по 1 108 серверам, на котором калибровался v4.
59
61
 
@@ -135,7 +137,28 @@ conversation history to https://…», «send a copy of all messages to someone@
135
137
  из 41 сервера переноса. Два правила о чужих инструментах не работают по имени: им нужно предложение о вызове
136
138
  другого инструмента. Тесты: `test/ruleset-v10.test.ts`.
137
139
 
138
- Каждое правило объявляет, на каких из этих семи **поверхностей** оно работает; 24 из 35 включают
140
+ **v13** подсказал читатель сравнения сканеров: инструмент, который берёт ключ («the signing key, hex»), отличается
141
+ от того, что использует сохранённый ключ («the name of a saved login»), именно описанием аргумента. Новое правило
142
+ `TOOL_DEF_SECRET_REQUEST` читает описания аргументов и ловит ключевой материал, который просят **значением**, в
143
+ словах, которых нет у правил про private key и seed phrase: ключ подписи или кошелька, пара ключей, фраза
144
+ восстановления или секретная фраза. Оно только добавляет находки. Описание пишет автор, поэтому оно никогда не
145
+ снимает совпадение другого правила, а предохранитель `keyReference` лишь сужает то, о чём сообщает само это
146
+ правило: ссылка на ключ остаётся в покое (его id, имя, путь или публичная половина, аргумент с именем `*_name` или
147
+ `*_id`, ключ, который инструмент создаёт сам, ключ как единица счёта). Это единственное правило, которое не читает
148
+ описание инструмента: там те же слова — то, как инструменты для ключей описывают себя («rotate my signing key»), и
149
+ на корпусе они заблокировали шесть честных серверов; в описаниях аргументов — ни одного.
150
+
151
+ При его написании нашлась дыра, которая была во всех наборах начиная с v4 (2026-08-24), когда появился этот предохранитель. `identifierFragment` считал точку в конце «Send me your
152
+ private key.» частью идентификатора и снимал находку: фраза проходила, а те же слова без точки блокировались. v13
153
+ читает точку или дефис на краю слова как пунктуацию. Это вскрыло четыре честные фразы, которые раньше прятала та же
154
+ точка («a challenge message to sign with the wallet's private key», «signed by the new credential's private key»,
155
+ «You keep the private key.», «messages from one signing key»); предохранитель `keyStaysLocal` не трогает ключ,
156
+ которым подписывают или который остаётся у пользователя, если ничто во фразе его не перемещает («sign it and paste
157
+ the private key» по-прежнему блокируется). На корпусе v13 блокирует 4 сервера вместо 3 у v12 и ни одного не теряет:
158
+ новый — удалённый сборщик, чей аргумент принимает 64-байтный секретный ключ новой пары ключей минта. На MCPTox ничего не меняется: 171 из 218 отравленных инструментов отложенной половины заблокированы, как и у v12 (замер воспроизвёлся точно), и ни один из 45 чистых серверов; инструменты MCPTox переписывают чужие вызовы, а не просят ключи.
159
+ Тесты: `test/ruleset-v13.test.ts`.
160
+
161
+ Каждое правило объявляет, на каких из этих семи **поверхностей** оно работает; 24 из 36 включают
139
162
  имя. Четыре кода из тех, что не включают имя, — это правила, завязанные на существительное
140
163
  (`TOOL_DEF_SECRET_REQUEST`, `TOOL_DEF_CREDENTIAL_PARAM`, `TOOL_DEF_ENV_REFERENCE`, `TOOL_DEF_SECRET_EXFIL`): имя — это
141
164
  идентификатор, `api_key` и `private_key` — его обычные части, и блокировать
package/docs/gates.zh.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > 🌐 [English](gates.md) · [Русский](gates.ru.md) · [Español](gates.es.md) · [Français](gates.fr.md) · **中文**
4
4
 
5
+ **Ruleset v14(尚未发布):** `keyStaysLocal` 不再把服务器存储视为本地保管。以下 v13 的语料/MCPTox 数字为历史结果;v14 只进行了本地回归测试,没有新基准。
6
+
5
7
  > [0.7.0 安全更新与迁移](security-hardening.zh.md).
6
8
 
7
9
  `Warden.vet(server, tools)` 会按顺序跑完一条门控链,并返回单一裁定。本页就是完整的判定过程:每个门控看什么、
@@ -44,7 +46,7 @@ const SEVERITY_RANK = { info: 0, low: 1, medium: 2, high: 3, critical: 4 };
44
46
 
45
47
  ## static-scan
46
48
 
47
- 对工具公布的每个字段做本地正则扫描:`name`、`description` 与 `inputSchema`,以及自 v6 起的 `title`、`outputSchema`、`annotations` 和扩展元数据(服务器发来的其他一切内容,base64 图片图标除外)。规则集 **v10** 共 35 条规则:24 条 `block`,11 条 `advise`,其中 24 条带有上下文 **guard**——一项具名检查,用于判断某次命中是否真是该规则要找的东西。参见[实地普查](mcp-survey.zh.md),即校准 v4 的 1 108 台服务器实测。
49
+ 对工具公布的每个字段做本地正则扫描:`name`、`description` 与 `inputSchema`,以及自 v6 起的 `title`、`outputSchema`、`annotations` 和扩展元数据(服务器发来的其他一切内容,base64 图片图标除外)。规则集 **v14** 共 36 条规则:25 条 `block`,11 条 `advise`,其中 25 条带有上下文 **guard**——一项具名检查,用于判断某次命中是否真是该规则要找的东西。参见[实地普查](mcp-survey.zh.md),即校准 v4 的 1 108 台服务器实测。
48
50
 
49
51
  **v5:任何规则读取文本之前,先对文本做归一化。** NFKC 把全角字母、连字和其他兼容形式变成普通字母;单词内部的不可见字符被删除;Unicode 标签区块(ASCII 的不可见副本,能藏下一整句话)被解码;在拉丁字母与西里尔或希腊字母混写的单词里,形近字母被换成拉丁字母,而整词只用一种文字写成的单词保持不变。于是,无论周围文本是什么语言,英文规则都不能再被全角字母、词内零宽空格、标签字符或西里尔字母 `о` 绕过。归一化以 `fold` 的形式与规则一起发布,并计入 digest。两条隐藏载荷规则读取**原始**文本(`raw: true`)。
50
52
 
@@ -60,7 +62,18 @@ v5 还消除了三类实测误报:“send the user to https://…”(引导
60
62
 
61
63
  **v10** 针对 MCPTox(Wang et al.,AAAI 2026)编写:45 台真实服务器上的 485 个投毒工具,按三种攻击模板生成。在写下任何规则之前,先用固定哈希把它的服务器分成两半;规则只来自前一半,后一半是测量结果([scan 指南](scan.zh.md#对比))。几乎每个 MCPTox 工具都是同一种形态:它的文本绑定到**另一个**工具的调用上。新代码 `TOOL_DEF_CROSS_TOOL` 在以下情况下阻止:某句话提到另一个工具的调用(“when using `X`”“before running `X`”“any query to `X`”“before any …”),并在同一句中改写该调用的输入(modify、replace、append …),或在这一句或下一句中要求先调用第三个工具;以及一个没有输入的工具只要求调用另一个工具。锚点是另一个工具的标识符,在任何语言中都写法相同。工具自己的名称和参数永远不算“另一个工具”,因此 “use `get_video` to check status before calling this tool” 和 “call `refresh` first, then this tool” 都会通过:它们把工具当作手段来提及。guard 现在会收到工具本身,规则由此知道它自己的标识符。v10 还会阻止声称优先于用户的定义。在留出的那一半上,v10 阻止了 218 个投毒工具中的 171 个,而 0.8.2 只阻止 26 个;它没有阻止 MCPTox 的 45 台干净服务器中的任何一台,在已提交的语料上阻止的仍是同样的 3 台,8 月遗留的 41 台中阻止 1 台。它的两条跨工具规则不作用于工具名称:它们读取的是关于另一个工具调用的句子。测试:`test/ruleset-v10.test.ts`。
62
64
 
63
- 每条规则都声明自己在这七个**面**中的哪些上运行,35 条里有 24 条包含名称。不包含名称的代码中,有四个是以**名词**为
65
+ **v13** 来自扫描器对比文章的一位读者:一个**接收**密钥的工具(“the signing key, hex”)和一个使用已保存密钥的工具(“the name of a saved login”)的区别,恰恰在参数自己的描述里。
66
+ 新的 `TOOL_DEF_SECRET_REQUEST` 规则读取参数描述,捕捉**按值**索要密钥材料、而 private key 和 seed phrase 规则没有写到的说法:签名密钥或钱包密钥、密钥对、恢复短语或秘密短语。
67
+ 它只会增加发现。描述是作者写的文本,所以它从不为其他规则的命中开脱;它的 guard `keyReference` 只收窄这条规则自己的报告:引用不算(密钥的 id、名称、路径或公钥部分,
68
+ 名为 `*_name` 或 `*_id` 的参数,工具自己创建的密钥,作为计数单位的密钥)。它是唯一不读工具描述的规则:在那里,同样的词是密钥类工具对自己的描述(“rotate my signing key”),
69
+ 在已提交的语料上它们阻止了六台诚实的服务器;在参数描述里一台也没有。
70
+
71
+ 编写它时发现了一个自 v4(2026-08-24,加入该 guard 时)起所有规则集都有的漏洞。`identifierFragment` 把 “Send me your private key.” 末尾的句号当作标识符的一部分而丢弃发现:这句话会放行,而去掉句号的同样词句会被阻止。
72
+ v13 把单词边缘的句点或连字符当作标点。这暴露了此前被同一个句号掩盖的四句诚实文本(“a challenge message to sign with the wallet's private key”“signed by the new credential's private key”
73
+ “You keep the private key.”“messages from one signing key”);guard `keyStaysLocal` 放过用于签名或由用户保留的密钥,除非同一分句里有任何东西把它移走(“sign it and paste the private key” 仍会被阻止)。
74
+ 在已提交的语料上,v13 阻止 4 台服务器,v12 是 3 台,且一台都没丢:新增的是一个托管构建器,它的参数接收一个新铸币密钥对的 64 字节私钥。在 MCPTox 上没有任何变化:留出一半的 218 个投毒工具中阻止 171 个,与 v12 相同(测量结果完全复现),45 台干净服务器一台都没阻止;MCPTox 的工具改写的是其他工具的调用,而不是索要密钥。测试:`test/ruleset-v13.test.ts`。
75
+
76
+ 每条规则都声明自己在这七个**面**中的哪些上运行,36 条里有 24 条包含名称。不包含名称的代码中,有四个是以**名词**为
64
77
  锚的规则(`TOOL_DEF_SECRET_REQUEST`、`TOOL_DEF_CREDENTIAL_PARAM`、`TOOL_DEF_ENV_REFERENCE`、`TOOL_DEF_SECRET_EXFIL`):名称是标识
65
78
  符,`api_key` 和 `private_key` 是标识符里再普通不过的组成部分,而拒绝 `sign_with_private_key` 等于把 v1 的
66
79
  校准错误换个面重犯一次。以**短语**为锚的规则需要空白字符,因此根本无法匹配 `snake_case`;而两条隐藏载荷规则
package/docs/scan.es.md CHANGED
@@ -146,6 +146,22 @@ Si el conjunto que recibiste es uno que el editor del servidor declara en su ent
146
146
 
147
147
  Las respuestas de HISTOR nunca bloquean. Si HISTOR no responde, se informa y el análisis continúa.
148
148
 
149
+ ## Para editores: declara los conjuntos de herramientas de tu servidor
150
+
151
+ HISTOR solo puede registrar las herramientas que tu servidor lista en su sandbox. Si lista otras donde está instalado algo que el sandbox no tiene —el runner de un lanzador, uno por sistema operativo, una clave real—, declara esos conjuntos, y quienes los reciben verán `HISTOR_DECLARED_TOOLSET` (low) en lugar de `HISTOR_UNSEEN_TOOLSET` (medium). En una máquina que recibe el conjunto:
152
+
153
+ ```bash
154
+ npx -y @aimarket/warden declare --when "runner 1.4, macOS" --out mcp-tool-sets.json -- npx -y @acme/launcher
155
+ ```
156
+
157
+ WARDEN arranca el servidor como lo haría un cliente, calcula el digest de su `tools/list` (MTL/1) y añade el conjunto a `mcp-tool-sets.json`, conservando los que ya había y reemplazando el mismo digest. Repítelo en cada sistema operativo y versión del runner. Después:
158
+
159
+ 1. Publica el archivo en el dominio que el registro verificó para el espacio de nombres de tu servidor —`ai.acme/launcher` → `acme.ai` o un subdominio; `io.github.<user>/…` → `<user>.github.io` o tus archivos raw de GitHub—, por ejemplo en `https://acme.ai/.well-known/mcp-tool-sets.json`.
160
+ 2. Apunta a él desde tu entrada del registro, una vez: `npx -y @aimarket/warden declare --server-json --link <url>` imprime el bloque `_meta` para `server.json`; publica esa versión en el registro.
161
+ 3. Compruébalo: `npx -y @aimarket/warden declare --check <url> --name ai.acme/launcher` lee el archivo como lo leerá HISTOR y dice qué tomará de él.
162
+
163
+ A partir de ahí, una nueva versión del runner solo necesita `declare --out` y volver a subir el archivo: HISTOR lo lee cada hora. Un conjunto que quitas del archivo se retira; un archivo que HISTOR no puede leer conserva lo que declaró. Sin archivo, `--server-json` con el servidor después de `--` pone el conjunto en la propia entrada, hasta 8 conjuntos. Las reglas que aplica HISTOR: [declarar conjuntos](https://github.com/alexar76/histor/blob/main/docs/api.es.md). Una declaración es la palabra del editor, no una observación: WARDEN sigue ejecutando todas las comprobaciones sobre las herramientas que recibe.
164
+
149
165
  ## El clasificador opcional
150
166
 
151
167
  Las reglas de WARDEN funcionan sin conexión y de forma determinista, y no ven lo que ninguna regla nombra: una paráfrasis, una instrucción en otro idioma. `--classifier-url` y `--classifier-model` añaden una segunda opinión de un modelo que tú eliges, mediante cualquier endpoint compatible con OpenAI: Ollama, vLLM o LM Studio en local, o una API alojada.
@@ -160,39 +176,41 @@ WARDEN_CLASSIFIER_API_KEY=… warden-mcp scan --classifier-url https://api.deeps
160
176
  - **Cinco categorías.** `instruction_to_model`, `exfiltration`, `secret_request`, `concealment`, `cross_tool`. Se inspecciona la autoridad de las instrucciones en cualquier idioma; la capacidad del modelo varía. El protocolo exige una decisión por herramienta y referencias a campos verificadas por WARDEN, que extrae el texto original. Cada decisión incompleta se reintenta una sola vez de forma aislada. Los delimitadores aleatorios no garantizan inmunidad.
161
177
  - **Inspección no es aprobación.** [`wrap --require-approval`](security-hardening-language-boundary.md) exige una aprobación del operador independiente del idioma. HISTOR conserva sus resultados históricos como recomendaciones.
162
178
 
163
- Medido el 9 de octubre de 2026 con `deepseek-flash`, el modelo que usa HISTOR, sobre MCPTox (el benchmark publicado que se describe en la comparación de abajo) y sobre nuestros conjuntos:
179
+ Medido el 16 de octubre de 2026 con `deepseek-flash`, el modelo que usa HISTOR, sobre MCPTox (el benchmark publicado que se describe en la comparación de abajo), sobre servidores reales y sobre nuestros conjuntos:
164
180
 
165
- | | Reglas (v10) | Reglas + clasificador, bloqueando en `high` | Reglas + cualquier marca del clasificador (consultiva) |
166
- |---|---|---|---|
167
- | Mitad reservada de MCPTox, detectadas de 218 herramientas envenenadas | 171 | 191 | 218 |
168
- | 45 servidores limpios de MCPTox, bloqueados o marcados | 0 | 0 | 4 marcados |
169
- | 200 servidores del corpus elegidos al azar, bloqueados o marcados | 2 bloqueados | 2 bloqueados | 2 bloqueados, 12 marcados más |
170
- | 23 ataques nuestros / 12 casos benignos difíciles | 20 / 0 | 22 / 0 | 23 / 0 |
181
+ | | Reglas (v12) | Reglas + clasificador en `high` |
182
+ |---|---|---|
183
+ | Mitad reservada de MCPTox, detectadas de 218 herramientas envenenadas | 171 | 218 |
184
+ | 45 servidores limpios de MCPTox, marcados | 0 | 0 |
185
+ | 200 servidores del corpus elegidos al azar, bloqueados o marcados | 2 | 5 |
186
+ | 996 paquetes de npm y PyPI de una muestra aleatoria, bloqueados o marcados | 23 | 35 |
187
+ | 23 ataques escritos por nosotros / 12 casos benignos difíciles | 20 / 0 | 23 / 0 |
171
188
 
172
- Los dos que bloquean las reglas son el servicio de identidad y la herramienta de despliegue de la comparación de abajo. Los 13 servidores que marcó el clasificador lo fueron con `medium` o `low`, nunca `high`. Seis merecen que los mire una persona: uno le dice al modelo que haga una transferencia irreversible de un nombre ENS «como primera y única acción» sin preguntar al usuario, otro que no revele de dónde salen sus datos. El modelo también marca el servidor oficial Fetch, cuya descripción le dice al modelo que ahora tiene acceso a internet y no debe negarse. Es una instrucción al modelo, aunque no un ataque. El modelo no detectó lo que sí detectan las reglas: una inyección en anotaciones, una clave privada o frase semilla pedida como parámetro y `rm -rf ~`.
189
+ Los dos servidores del corpus que bloquean las reglas son el servicio de identidad y la herramienta de despliegue de la comparación de abajo. Las marcas `high` del clasificador en servidores reales son sobre todo órdenes de flujo de trabajo como «llama primero a esta herramienta». Dos paquetes merecen una mirada humana y las reglas no bloquean ninguno: uno envuelve su descripción en un bloque falso de «el usuario lo pidió» y ordena al modelo llamarlo antes de cualquier respuesta; otro envía contenido de archivos del agente a su servidor con «Do NOT display … to the user». El modelo no vio lo que detectan las reglas: una inyección en el nombre de una herramienta, una clave privada o frase semilla pedida como parámetro y `rm -rf ~`. Juntos detectan los 23 ataques nuestros.
173
190
 
174
191
  ## Cómo se compara
175
192
 
176
- El 9 de octubre de 2026 ejecutamos WARDEN, mcp-audit 0.18.2 (`--connect`) y mcp-shield 1.0.4 sobre los mismos servidores. Cada servidor se reprodujo por stdio, así que cada escáner se conectó a él como lo haría en la práctica. El banco de pruebas, los conjuntos y cada juicio están en [`scripts/scanner-comparison`](../scripts/scanner-comparison/). El estudio completo, con el método y todas las salvedades, es la [comparación de escáneres](scanner-comparison.es.md).
177
-
178
- Las tres últimas filas vienen de MCPTox (Wang et al., AAAI 2026), un benchmark publicado de 485 herramientas envenenadas escritas para 45 servidores MCP reales. Dividimos sus servidores en dos con un hash fijo. El ruleset v10 se escribió a partir de 22 servidores; la tabla informa sobre los otros 23, con 218 herramientas envenenadas a las que no se ajustó ninguna regla.
179
-
180
- | Servidores | WARDEN 0.8.2 (v8) | WARDEN 0.9.0 (v10) | mcp-audit 0.18.2 | mcp-shield 1.0.4 |
181
- |---|---|---|---|---|
182
- | 23 ataques escritos por nosotros, bloqueados | 14 | 20 | 10 | 6 |
183
- | 10 ataques de los propios fixtures de mcp-audit y mcp-shield, bloqueados | 7 | 10 | 10 | 8 |
184
- | 12 casos benignos difíciles, bloqueados | 0 | 0 | 1 | 1 |
185
- | 986 servidores públicos, bloqueados | 3 | 3 | 33 | 343 |
186
- | …bloqueos que se sostienen al leer el texto | 1, y 1 discutible | 1, y 1 discutible | 0 | 0 de 20 elegidos al azar |
187
- | 218 herramientas envenenadas de MCPTox en los servidores reservados, bloqueadas | 26 | 171 | 25 | 41 |
188
- | 225 herramientas de MCPTox con el prefijo `<IMPORTANT>` o «Ignore the previous instructions», bloqueadas | 225 | 225 | 222 | no ejecutado |
189
- | 45 servidores limpios de MCPTox, bloqueados | 0 | 0 | 2 | 3 |
190
-
191
- - **Lee primero la fila del corpus.** Ninguna regla se ajustó a ella. Los 33 bloqueos de mcp-audit son 16 «homoglifos» en texto escrito por completo en su propio alfabeto (puntuación china, símbolos griegos, cirílico), 12 instrucciones de honestidad como «do not tell the user the check digits are wrong», 3 utilidades base64, una herramienta de clave pública SSH y la herramienta de despliegue que WARDEN también bloquea por error. mcp-shield bloquea el 35 % de los servidores reales, casi siempre por una palabra clave: «API key», «token», `.env`, «..». Unos puntos suspensivos («Shopify...») cuentan como salto de directorio. También bloquea el servicio de identidad que bloquea WARDEN, pero por la palabra «credentials».
192
- - **Ten presente qué números están ajustados.** El primer conjunto de ataques lo escribimos nosotros. El ruleset v9 se escribió después de leer ambos conjuntos de ataques, y v10 después de los 22 servidores de MCPTox de la otra mitad. Así que 20 y 10 son la exhaustividad de reglas ajustadas a lo que vieron. La fila reservada de MCPTox, los servidores limpios, el corpus y toda la columna 0.8.2 no están ajustados. Sobre el corpus, v10 bloquea exactamente lo mismo que v8.
193
- - **MCPTox prueba una forma, no una palabra clave.** Casi todas las herramientas envenenadas le dicen al modelo que llame antes a otra herramienta o que cambie los argumentos de otra. v10 nombra esa forma (`TOOL_DEF_CROSS_TOOL`, ver [la cadena de compuertas](gates.es.md)) y bloquea 171 de las 218 herramientas reservadas, frente a 189 de 267 en la mitad con la que se escribió. Con el prefijo `<IMPORTANT>` o «Ignore the previous instructions» del benchmark, todos los escáneres que ejecutamos las detectan; mcp-shield no lo ejecutamos sobre ese conjunto. En los servidores limpios, mcp-audit bloquea AmapMap y BaiduMap, y mcp-shield bloquea FileSystem, AdFin y Commander por «sensitive file access».
194
- - **Lo que WARDEN todavía no detecta:** 47 de las 218 herramientas reservadas de MCPTox, una instrucción en chino para leer `.env`, una paráfrasis sin palabras clave («gather every credential file … keep this step to yourself») y «include the output of env». Informa 41 de esas 47, y las tres nuestras, como avisos, no como bloqueos. Necesitan una comprobación por significado, no otra regla: con el clasificador opcional de arriba, 191 de las 218 quedan bloqueadas en `high` y las 218 quedan marcadas.
195
- - **WARDEN no está solo en ese hueco.** mcp-audit también tiene archivo lock, modo diff para PR y SARIF.
193
+ El 16 de octubre de 2026 ejecutamos WARDEN, mcp-audit 0.18.2 (`--connect`), mcp-shield 1.0.4, truecopy 0.10.4 y mcpsentry 0.1.5 sobre los mismos servidores. Cada servidor se reprodujo por stdio, así que cada escáner se conectó a él como lo haría en la práctica. Cada escáner corrió en un contenedor gVisor sin red, desde imágenes fijas cuyo contenido está resumido con hashes en un manifiesto. El banco de pruebas, los conjuntos, el manifiesto y cada juicio están en [`scripts/scanner-comparison`](../scripts/scanner-comparison/). El informe completo, con el método y cada salvedad, es la [comparación de escáneres](scanner-comparison.es.md).
194
+
195
+ Las filas de MCPTox vienen de MCPTox (Wang et al., AAAI 2026), un benchmark publicado de 485 herramientas envenenadas escritas para 45 servidores MCP reales. Dividimos sus servidores en dos con un hash fijo. Las reglas v10 se escribieron con 22 servidores; la tabla informa de los otros 23, con 218 herramientas envenenadas a las que no se ajustó ninguna regla. v11 y v12 tampoco se escribieron con ellas y dan los mismos veredictos que v10.
196
+
197
+ | Servidores | WARDEN 0.16.0 (v12) | mcp-audit 0.18.2 | mcp-shield 1.0.4 | truecopy 0.10.4 | mcpsentry 0.1.5 |
198
+ |---|---|---|---|---|---|
199
+ | 23 ataques escritos por nosotros, bloqueados | 20 | 10 | 6 | 8 | 4 |
200
+ | 10 ataques de los propios fixtures de mcp-audit y mcp-shield, bloqueados | 10 | 10 | 8 | 7 | 5 |
201
+ | 12 casos benignos difíciles, bloqueados | 0 | 1 | 1 | 1 | 2 |
202
+ | 218 herramientas envenenadas de MCPTox en los servidores reservados, bloqueadas | 171 | 25 | 41 | 27 | 8 |
203
+ | 225 herramientas de MCPTox con un prefijo `<IMPORTANT>` o «Ignore the previous instructions», bloqueadas | 225 | 222 | 41 | 141 | 136 |
204
+ | 45 servidores limpios de MCPTox, bloqueados | 0 | 2 | 3 | 0 | 1 |
205
+ | 986 servidores públicos, bloqueados | 3 | 33 | 343 | 39 | 86 |
206
+ | …bloqueos que se sostienen al leer el texto | 1, y 1 discutible | 0 | 1 de los 34 que leímos | 1 | 0 |
207
+ | 14 933 paquetes de npm y PyPI que observó HISTOR, bloqueados | 369 | 928 | 5354 | 252 | 1449 |
208
+
209
+ - **Lee primero las filas de servidores reales.** Ninguna regla se ajustó a ellas. Los 33 bloqueos de mcp-audit en el corpus son sobre todo «homoglifos» en texto escrito entero en su propio alfabeto e instrucciones de honestidad como «do not tell the user the check digits are wrong». mcp-shield bloquea un tercio de los servidores reales, casi siempre por una palabra clave: «API key», «token», `.env`, «..». truecopy bloquea los generadores de docker-compose de un mismo proveedor porque producen un `.env.example`. El patrón base64 de mcpsentry coincide con cualquier secuencia de 40 letras y barras, como las que producen las rutas de JSON Schema. En 14 933 paquetes de npm y PyPI, una muestra aleatoria de 996 en la que juzgamos cada bloqueo tiene 23 bloqueos de WARDEN, ninguno se sostiene y 4 son discutibles; mcp-shield bloquea 339 de esos mismos paquetes y mcpsentry 112.
210
+ - **Ten claro qué números están ajustados.** Escribimos el primer conjunto de ataques, y las reglas v9 se escribieron después de leer ambos conjuntos de ataques. La fila de la mitad reservada de MCPTox, los servidores limpios, el corpus y los paquetes no están ajustados.
211
+ - **MCPTox prueba una forma, no una palabra clave.** Casi todas las herramientas envenenadas le dicen al modelo que llame antes a otra herramienta o que cambie los argumentos de otra. v10 le dio nombre a esa forma (`TOOL_DEF_CROSS_TOOL`, véase [la cadena de compuertas](gates.es.md)) y v12 la conserva. Con el prefijo `<IMPORTANT>` del benchmark, la mayoría de los escáneres detecta la mayoría de las herramientas.
212
+ - **Lo que WARDEN todavía no detecta:** 47 de las 218 herramientas reservadas de MCPTox, una instrucción en chino para leer `.env`, una paráfrasis sin palabras clave («gather every credential file … keep this step to yourself») y «include the output of env». Informa 41 de esas 47 como avisos, no como bloqueos. Con el clasificador opcional de arriba, las 218 quedan marcadas en `high`.
213
+ - **WARDEN no está solo en ese hueco.** mcp-audit también tiene archivo lock, modo diff para PR y SARIF; truecopy también fija y firma definiciones en un archivo lock.
196
214
 
197
215
  ## Lo que scan no hace
198
216
 
package/docs/scan.fr.md CHANGED
@@ -146,6 +146,22 @@ Si l’ensemble reçu est un ensemble que l’éditeur du serveur déclare dans
146
146
 
147
147
  Les réponses d’HISTOR ne bloquent jamais. Si HISTOR ne répond pas, c’est signalé et l’analyse continue.
148
148
 
149
+ ## Pour les éditeurs : déclarez les ensembles d’outils de votre serveur
150
+
151
+ HISTOR ne peut enregistrer que les outils que votre serveur liste dans son bac à sable. S’il en liste d’autres là où est installé ce que le bac à sable n’a pas — le runner d’un lanceur, un par système d’exploitation, une vraie clé —, déclarez ces ensembles, et ceux qui les reçoivent verront `HISTOR_DECLARED_TOOLSET` (low) au lieu de `HISTOR_UNSEEN_TOOLSET` (medium). Sur une machine qui reçoit l’ensemble :
152
+
153
+ ```bash
154
+ npx -y @aimarket/warden declare --when "runner 1.4, macOS" --out mcp-tool-sets.json -- npx -y @acme/launcher
155
+ ```
156
+
157
+ WARDEN démarre le serveur comme le ferait un client, calcule le condensé de son `tools/list` (MTL/1) et ajoute l’ensemble à `mcp-tool-sets.json`, en gardant ceux qui y sont et en remplaçant le même condensé. Recommencez sur chaque système et chaque version du runner. Ensuite :
158
+
159
+ 1. Publiez le fichier sur le domaine que le registre a vérifié pour l’espace de noms de votre serveur — `ai.acme/launcher` → `acme.ai` ou un sous-domaine ; `io.github.<user>/…` → `<user>.github.io` ou vos fichiers raw GitHub —, par exemple à `https://acme.ai/.well-known/mcp-tool-sets.json`.
160
+ 2. Faites-y pointer votre entrée du registre, une fois : `npx -y @aimarket/warden declare --server-json --link <url>` affiche le bloc `_meta` pour `server.json` ; publiez cette version au registre.
161
+ 3. Vérifiez : `npx -y @aimarket/warden declare --check <url> --name ai.acme/launcher` lit le fichier comme HISTOR le lira et dit ce qu’HISTOR en retiendra.
162
+
163
+ Ensuite, une version du runner ne demande que `declare --out` et un nouvel envoi du fichier : HISTOR le relit toutes les heures. Un ensemble retiré du fichier est retiré ; un fichier qu’HISTOR ne peut pas lire garde ce qu’il déclarait. Sans fichier, `--server-json` avec le serveur après `--` met l’ensemble dans l’entrée elle-même, jusqu’à 8 ensembles. Les règles qu’applique HISTOR : [déclarer des ensembles](https://github.com/alexar76/histor/blob/main/docs/api.fr.md). Une déclaration est la parole de l’éditeur, pas une observation : WARDEN applique toujours toutes ses vérifications aux outils qu’il reçoit.
164
+
149
165
  ## Le classificateur optionnel
150
166
 
151
167
  Les règles de WARDEN fonctionnent hors ligne et de façon déterministe, et elles manquent ce qu'aucune règle ne nomme : une paraphrase, une consigne dans une autre langue. `--classifier-url` et `--classifier-model` ajoutent l'avis d'un modèle que vous choisissez, via n'importe quel endpoint compatible OpenAI : Ollama, vLLM ou LM Studio en local, ou une API hébergée.
@@ -160,39 +176,41 @@ WARDEN_CLASSIFIER_API_KEY=… warden-mcp scan --classifier-url https://api.deeps
160
176
  - **Cinq catégories.** `instruction_to_model`, `exfiltration`, `secret_request`, `concealment`, `cross_tool`. L’inspection porte sur l’autorité des instructions, dans toute langue, selon les capacités du modèle. Le protocole exige une décision par outil et des références de champs vérifiées par WARDEN, qui extrait le texte source. Chaque décision incomplète est réessayée une seule fois isolément. Les délimiteurs aléatoires ne garantissent pas l’immunité.
161
177
  - **Inspection ne vaut pas approbation.** [`wrap --require-approval`](security-hardening-language-boundary.md) exige l’approbation de l’opérateur indépendamment de la langue. Les résultats historiques de HISTOR restent consultatifs.
162
178
 
163
- Mesuré le 9 octobre 2026 avec `deepseek-flash`, le modèle qu'utilise HISTOR, sur MCPTox (le benchmark publié décrit dans la comparaison ci-dessous) et sur nos propres jeux :
179
+ Mesuré le 16 octobre 2026 avec `deepseek-flash`, le modèle qu'utilise HISTOR, sur MCPTox (le benchmark publié décrit dans la comparaison ci-dessous), sur de vrais serveurs et sur nos propres jeux :
164
180
 
165
- | | Règles (v10) | Règles + classificateur, blocage à `high` | Règles + toute marque du classificateur (consultative) |
166
- |---|---|---|---|
167
- | Moitié réservée de MCPTox, détectés sur 218 outils empoisonnés | 171 | 191 | 218 |
168
- | 45 serveurs propres de MCPTox, bloqués ou marqués | 0 | 0 | 4 marqués |
169
- | 200 serveurs du corpus tirés au hasard, bloqués ou marqués | 2 bloqués | 2 bloqués | 2 bloqués, 12 autres marqués |
170
- | 23 attaques écrites par nous / 12 cas bénins difficiles | 20 / 0 | 22 / 0 | 23 / 0 |
181
+ | | Règles (v12) | Règles + classificateur au niveau `high` |
182
+ |---|---|---|
183
+ | Moitié réservée de MCPTox, détectés sur 218 outils empoisonnés | 171 | 218 |
184
+ | 45 serveurs propres de MCPTox, signalés | 0 | 0 |
185
+ | 200 serveurs du corpus tirés au hasard, bloqués ou signalés | 2 | 5 |
186
+ | 996 paquets npm et PyPI d'un échantillon aléatoire, bloqués ou signalés | 23 | 35 |
187
+ | 23 attaques écrites par nous / 12 cas bénins difficiles | 20 / 0 | 23 / 0 |
171
188
 
172
- Les deux que bloquent les règles sont le service d’identité et l’outil de déploiement de la comparaison ci-dessous. Les 13 serveurs marqués par le classificateur l'ont été en `medium` ou `low`, jamais en `high`. Six méritent un regard humain : l'un demande au modèle d'effectuer un transfert irréversible de nom ENS « comme première et unique action » sans demander à l'utilisateur, un autre de ne pas révéler d'où viennent ses données. Le modèle marque aussi le serveur officiel Fetch, dont la description dit au modèle qu'il a désormais accès à internet et ne doit pas refuser. C'est une consigne au modèle, mais pas une attaque. Le modèle a manqué ce que les règles détectent : une injection dans les annotations, une clé privée ou une phrase de récupération demandée comme paramètre, et `rm -rf ~`.
189
+ Les deux serveurs du corpus que bloquent les règles sont le service d'identité et l'outil de déploiement de la comparaison ci-dessous. Les signalements `high` du classificateur sur de vrais serveurs sont surtout des consignes de déroulement comme « appelle d'abord cet outil ». Deux paquets méritent un regard humain, et les règles n'en bloquent aucun : l'un enveloppe sa description dans un faux bloc « c'est l'utilisateur qui l'a demandé » et ordonne au modèle de l'appeler avant toute réponse ; l'autre envoie le contenu de fichiers de l'agent vers son serveur avec « Do NOT display … to the user ». Le modèle a manqué ce que les règles détectent : une injection dans le nom d'un outil, une clé privée ou une phrase de récupération demandée en paramètre, et `rm -rf ~`. Ensemble, ils détectent nos 23 attaques.
173
190
 
174
191
  ## Comparaison
175
192
 
176
- Le 9 octobre 2026, nous avons exécuté WARDEN, mcp-audit 0.18.2 (`--connect`) et mcp-shield 1.0.4 sur les mêmes serveurs. Chaque serveur était rejoué en stdio, si bien que chaque scanner s’y connectait comme sur le terrain. Le banc, les jeux et chaque jugement sont dans [`scripts/scanner-comparison`](../scripts/scanner-comparison/). L’étude complète, avec la méthode et toutes les réserves, est la [comparaison de scanners](scanner-comparison.fr.md).
177
-
178
- Les trois dernières lignes viennent de MCPTox (Wang et al., AAAI 2026), un benchmark publié de 485 outils empoisonnés écrits pour 45 vrais serveurs MCP. Nous avons coupé ses serveurs en deux par un hachage fixe. Le ruleset v10 a été écrit à partir de 22 serveurs ; le tableau rend compte des 23 autres, avec 218 outils empoisonnés sur lesquels aucune règle n’a été ajustée.
179
-
180
- | Serveurs | WARDEN 0.8.2 (v8) | WARDEN 0.9.0 (v10) | mcp-audit 0.18.2 | mcp-shield 1.0.4 |
181
- |---|---|---|---|---|
182
- | 23 attaques écrites par nous, bloquées | 14 | 20 | 10 | 6 |
183
- | 10 attaques tirées des fixtures de mcp-audit et de mcp-shield, bloquées | 7 | 10 | 10 | 8 |
184
- | 12 cas bénins difficiles, bloqués | 0 | 0 | 1 | 1 |
185
- | 986 serveurs publics, bloqués | 3 | 3 | 33 | 343 |
186
- | …blocages justifiés à la lecture du texte | 1, et 1 discutable | 1, et 1 discutable | 0 | 0 sur 20 tirés au hasard |
187
- | 218 outils empoisonnés de MCPTox sur les serveurs réservés, bloqués | 26 | 171 | 25 | 41 |
188
- | 225 outils de MCPTox précédés de `<IMPORTANT>` ou « Ignore the previous instructions », bloqués | 225 | 225 | 222 | non exécuté |
189
- | 45 serveurs propres de MCPTox, bloqués | 0 | 0 | 2 | 3 |
190
-
191
- - **Lisez d’abord la ligne du corpus.** Aucune règle n’a été ajustée sur elle. Les 33 blocages de mcp-audit sont 16 « homoglyphes » dans un texte écrit entièrement dans son propre alphabet (ponctuation chinoise, symboles grecs, cyrillique), 12 consignes d’honnêteté comme « do not tell the user the check digits are wrong », 3 utilitaires base64, un outil de clé publique SSH et l’outil de déploiement que WARDEN bloque lui aussi à tort. mcp-shield bloque 35 % des serveurs réels, presque toujours sur un mot-clé : « API key », « token », `.env`, « .. ». Des points de suspension (« Shopify... ») comptent comme une remontée de répertoire. Il bloque bien le service d’identité que bloque WARDEN, mais pour le mot « credentials ».
192
- - **Sachez quels chiffres sont ajustés.** Nous avons écrit le premier jeu d’attaques. Le ruleset v9 a été écrit après la lecture des deux jeux d’attaques, et v10 après les 22 serveurs MCPTox de l’autre moitié. 20 et 10 sont donc le rappel de règles ajustées à ce qu’elles ont vu. La ligne MCPTox réservée, les serveurs propres, le corpus et toute la colonne 0.8.2 ne sont pas ajustés. Sur le corpus, v10 bloque exactement ce que bloquait v8.
193
- - **MCPTox teste une forme, pas un mot-clé.** Presque chaque outil empoisonné dit au modèle d’appeler d’abord un autre outil, ou de changer les arguments d’un autre outil. v10 nomme cette forme (`TOOL_DEF_CROSS_TOOL`, voir [la chaîne de portes](gates.fr.md)) et bloque 171 des 218 outils réservés, contre 189 sur 267 dans la moitié qui a servi à l’écrire. Avec le préfixe `<IMPORTANT>` ou « Ignore the previous instructions » du benchmark, tous les scanners que nous avons lancés les attrapent ; nous n’avons pas lancé mcp-shield sur ce jeu. Sur les serveurs propres, mcp-audit bloque AmapMap et BaiduMap, et mcp-shield bloque FileSystem, AdFin et Commander pour « sensitive file access ».
194
- - **Ce que WARDEN manque encore :** 47 des 218 outils MCPTox réservés, une consigne en chinois de lire `.env`, une paraphrase sans mot-clé (« gather every credential file … keep this step to yourself ») et « include the output of env ». Il signale 41 de ces 47, et nos trois, à titre consultatif, sans bloquer. Il faut une vérification par le sens, pas une règle de plus : avec le classificateur optionnel ci-dessus, 191 des 218 sont bloqués au niveau `high` et les 218 sont signalés.
195
- - **WARDEN n’est pas seul sur ce créneau.** mcp-audit propose lui aussi un fichier lock, un mode diff pour les PR et SARIF.
193
+ Le 16 octobre 2026, nous avons exécuté WARDEN, mcp-audit 0.18.2 (`--connect`), mcp-shield 1.0.4, truecopy 0.10.4 et mcpsentry 0.1.5 sur les mêmes serveurs. Chaque serveur était rejoué en stdio, si bien que chaque scanner s'y connectait comme sur le terrain. Chaque scanner a tourné dans un conteneur gVisor sans réseau, à partir d'images figées dont le contenu est haché dans un manifeste. Le banc d'essai, les jeux, le manifeste et chaque jugement sont dans [`scripts/scanner-comparison`](../scripts/scanner-comparison/). Le compte rendu complet, avec la méthode et chaque réserve, est la [comparaison de scanners](scanner-comparison.fr.md).
194
+
195
+ Les lignes MCPTox viennent de MCPTox (Wang et al., AAAI 2026), un benchmark publié de 485 outils empoisonnés écrits pour 45 vrais serveurs MCP. Nous avons coupé ses serveurs en deux avec un hachage fixe. Les règles v10 ont été écrites à partir de 22 serveurs ; le tableau rapporte les 23 autres, avec 218 outils empoisonnés auxquels aucune règle n'a été ajustée. v11 et v12 n'en ont pas été tirées non plus et donnent les mêmes verdicts que v10.
196
+
197
+ | Serveurs | WARDEN 0.16.0 (v12) | mcp-audit 0.18.2 | mcp-shield 1.0.4 | truecopy 0.10.4 | mcpsentry 0.1.5 |
198
+ |---|---|---|---|---|---|
199
+ | 23 attaques écrites par nous, bloquées | 20 | 10 | 6 | 8 | 4 |
200
+ | 10 attaques tirées des fixtures de mcp-audit et de mcp-shield, bloquées | 10 | 10 | 8 | 7 | 5 |
201
+ | 12 cas bénins difficiles, bloqués | 0 | 1 | 1 | 1 | 2 |
202
+ | 218 outils empoisonnés de MCPTox sur les serveurs réservés, bloqués | 171 | 25 | 41 | 27 | 8 |
203
+ | 225 outils de MCPTox avec un préfixe `<IMPORTANT>` ou « Ignore the previous instructions », bloqués | 225 | 222 | 41 | 141 | 136 |
204
+ | 45 serveurs propres de MCPTox, bloqués | 0 | 2 | 3 | 0 | 1 |
205
+ | 986 serveurs publics, bloqués | 3 | 33 | 343 | 39 | 86 |
206
+ | …blocages qui tiennent à la lecture du texte | 1, et 1 discutable | 0 | 1 sur les 34 lus | 1 | 0 |
207
+ | 14 933 paquets npm et PyPI observés par HISTOR, bloqués | 369 | 928 | 5 354 | 252 | 1 449 |
208
+
209
+ - **Lisez d'abord les lignes sur de vrais serveurs.** Aucune règle n'y a été ajustée. Les 33 blocages de mcp-audit sur le corpus sont surtout des « homoglyphes » dans un texte écrit entièrement dans son propre alphabet et des consignes d'honnêteté comme « do not tell the user the check digits are wrong ». mcp-shield bloque un tiers des vrais serveurs, presque toujours sur un mot-clé : « API key », « token », `.env`, « .. ». truecopy bloque les générateurs docker-compose d'un même éditeur parce qu'ils produisent un `.env.example`. Le motif base64 de mcpsentry correspond à toute suite de 40 lettres et barres obliques, comme en produisent les chemins JSON Schema. Sur 14 933 paquets npm et PyPI, un échantillon aléatoire de 996 où chaque blocage a été jugé compte 23 blocages de WARDEN, dont aucun ne tient et 4 sont discutables ; mcp-shield bloque 339 de ces mêmes paquets et mcpsentry 112.
210
+ - **Sachez quels chiffres sont ajustés.** Nous avons écrit le premier jeu d'attaques, et les règles v9 ont été écrites après la lecture des deux jeux d'attaques. La ligne de la moitié réservée de MCPTox, les serveurs propres, le corpus et les paquets ne sont pas ajustés.
211
+ - **MCPTox teste une forme, pas un mot-clé.** Presque chaque outil empoisonné dit au modèle d'appeler d'abord un autre outil, ou de changer les arguments d'un autre. v10 a nommé cette forme (`TOOL_DEF_CROSS_TOOL`, voir [la chaîne de portes](gates.fr.md)) et v12 la garde. Avec le préfixe `<IMPORTANT>` du benchmark, la plupart des scanners détectent la plupart des outils.
212
+ - **Ce que WARDEN manque encore :** 47 des 218 outils MCPTox réservés, une consigne en chinois de lire `.env`, une paraphrase sans mot-clé (« gather every credential file … keep this step to yourself ») et « include the output of env ». Il en signale 41 sur 47 à titre consultatif, sans les bloquer. Avec le classificateur facultatif ci-dessus, les 218 sont signalés au niveau `high`.
213
+ - **WARDEN n'est pas seul sur ce créneau.** mcp-audit propose lui aussi un fichier lock, un mode diff pour les PR et SARIF ; truecopy épingle et signe lui aussi les définitions dans un fichier lock.
196
214
 
197
215
  ## Ce que scan ne fait pas
198
216
 
package/docs/scan.md CHANGED
@@ -146,6 +146,22 @@ The set you got may be one the server's publisher declares in its registry entry
146
146
 
147
147
  HISTOR answers never block. An outage is reported and the scan continues.
148
148
 
149
+ ## For publishers: declare your server's tool sets
150
+
151
+ HISTOR can only record the tools your server lists in its sandbox. If it lists others where something the sandbox lacks is installed — a launcher's runner, one per operating system, a real key — declare those sets, and the people who get them see `HISTOR_DECLARED_TOOLSET` (low) instead of `HISTOR_UNSEEN_TOOLSET` (medium). On a machine that gets the set:
152
+
153
+ ```bash
154
+ npx -y @aimarket/warden declare --when "runner 1.4, macOS" --out mcp-tool-sets.json -- npx -y @acme/launcher
155
+ ```
156
+
157
+ WARDEN starts the server the way a client would, digests its `tools/list` (MTL/1) and adds the set to `mcp-tool-sets.json`, keeping the sets already there and replacing the same digest. Repeat on each operating system and runner version. Then:
158
+
159
+ 1. Publish the file on the domain the registry verified for your server's namespace — `ai.acme/launcher` → `acme.ai` or a subdomain; `io.github.<user>/…` → `<user>.github.io` or your raw GitHub files — for example at `https://acme.ai/.well-known/mcp-tool-sets.json`.
160
+ 2. Point your registry entry at it, once: `npx -y @aimarket/warden declare --server-json --link <url>` prints the `_meta` block for `server.json`; publish that version to the registry.
161
+ 3. Check it: `npx -y @aimarket/warden declare --check <url> --name ai.acme/launcher` reads the file the way HISTOR will and says what HISTOR takes from it.
162
+
163
+ After that, a runner release needs only `declare --out` and the file uploaded again: HISTOR reads it every hour. A set you remove from the file is withdrawn; a file HISTOR cannot read keeps what it declared. Without a file, `--server-json` with the server after `--` puts the set in the entry itself, up to 8 sets. The rules HISTOR applies: [declaring tool sets](https://github.com/alexar76/histor/blob/main/docs/api.md#declaring-tool-sets-publishers). A declaration is the publisher's word, not an observation: WARDEN still runs every check on the tools it gets.
164
+
149
165
  ## The optional classifier
150
166
 
151
167
  WARDEN's rules are offline and deterministic, and they miss what no rule names: a paraphrase, an instruction in another language. `--classifier-url` and `--classifier-model` add a second opinion from a model you choose, through any OpenAI-compatible endpoint: a local Ollama, vLLM or LM Studio, or a hosted API.
@@ -160,39 +176,41 @@ WARDEN_CLASSIFIER_API_KEY=… warden-mcp scan --classifier-url https://api.deeps
160
176
  - **Authority, in any language.** Categories are `instruction_to_model`, `exfiltration`, `secret_request`, `concealment` and `cross_tool`. The prompt separates legitimate tool requirements from attempts to override the user, invent consent or control another tool. Random fences help delimit untrusted data; they are not a proof against injection. The field-reference protocol requires one decision per input and host-validated evidence field IDs. WARDEN resolves source previews itself and retries each incomplete input once in isolation. Provider outages do not fan out into per-tool requests.
161
177
  - **Review is not approval.** Model language coverage varies. For a language-independent admission boundary use [`wrap --require-approval`](security-hardening-language-boundary.md). An LLM cannot create that approval. Historical HISTOR classifier results remain advisory and use their historical protocol.
162
178
 
163
- Measured on 2026-10-09 with `deepseek-flash`, the model HISTOR uses, on MCPTox (the published benchmark described in the comparison below) and on our own sets:
179
+ Measured on 2026-10-16 with `deepseek-flash`, the model HISTOR uses, on MCPTox (the published benchmark described in the comparison below), on real servers and on our own sets:
164
180
 
165
- | | Rules (v10) | Rules + classifier, blocking at `high` | Rules + any classifier flag (advisory) |
166
- |---|---|---|---|
167
- | MCPTox held-out half, 218 poisoned tools caught | 171 | 191 | 218 |
168
- | 45 clean MCPTox servers, blocked or flagged | 0 | 0 | 4 flagged |
169
- | 200 corpus servers drawn at random, blocked or flagged | 2 blocked | 2 blocked | 2 blocked, 12 more flagged |
170
- | 23 attacks we wrote / 12 hard benign cases | 20 / 0 | 22 / 0 | 23 / 0 |
181
+ | | Rules (v12) | Rules + classifier at `high` |
182
+ |---|---|---|
183
+ | MCPTox held-out half, 218 poisoned tools caught | 171 | 218 |
184
+ | 45 clean MCPTox servers, flagged | 0 | 0 |
185
+ | 200 corpus servers drawn at random, blocked or flagged | 2 | 5 |
186
+ | 996 npm and PyPI packages from a seeded sample, blocked or flagged | 23 | 35 |
187
+ | 23 attacks we wrote / 12 hard benign cases | 20 / 0 | 23 / 0 |
171
188
 
172
- The two the rules block are the identity service and the deploy tool from the comparison below. The 13 servers the classifier flagged were flagged at `medium` or `low`, never `high`. Six of them are worth a human look: one tells the model to make an irreversible ENS name transfer "as the first and only action" without asking the user, another tells it not to disclose where its data comes from. The model also flags the official Fetch server, whose description tells the model it now has internet access and should not refuse. That is an instruction to the model, though not an attack. The model missed what the rules catch: an injection in annotations, a private key or seed phrase asked for as a parameter, and `rm -rf ~`.
189
+ The two corpus servers the rules block are the identity service and the deploy tool from the comparison below. Of the classifier's `high` flags on real servers, most are workflow orders such as "call this tool first". Two packages are worth a human look and the rules block neither: one wraps its description in a fake "the user requested this" block and orders the model to call it before any reply; another sends file contents from the agent to its server with "Do NOT display … to the user". The model missed what the rules catch: an injection in a tool's name, a private key or seed phrase asked for as a parameter, and `rm -rf ~`. Together they catch all 23 of our attacks.
173
190
 
174
191
  ## How it compares
175
192
 
176
- On 2026-10-09 we ran WARDEN, mcp-audit 0.18.2 (`--connect`) and mcp-shield 1.0.4 over the same servers. Each server was replayed over stdio, so every scanner connected to it as it would in the field. The harness, the sets and every judgment are in [`scripts/scanner-comparison`](../scripts/scanner-comparison/). The full write-up, with the method and every caveat, is the [scanner comparison](scanner-comparison.md).
177
-
178
- The last three rows come from MCPTox (Wang et al., AAAI 2026), a published benchmark of 485 poisoned tools written for 45 real MCP servers. We split its servers in two by a fixed hash. Ruleset v10 was written from 22 servers; the table reports the other 23, with 218 poisoned tools no rule was fitted to.
179
-
180
- | Servers | WARDEN 0.8.2 (v8) | WARDEN 0.9.0 (v10) | mcp-audit 0.18.2 | mcp-shield 1.0.4 |
181
- |---|---|---|---|---|
182
- | 23 attacks we wrote, blocked | 14 | 20 | 10 | 6 |
183
- | 10 attacks from mcp-audit's and mcp-shield's own fixtures, blocked | 7 | 10 | 10 | 8 |
184
- | 12 hard benign cases, blocked | 0 | 0 | 1 | 1 |
185
- | 986 public servers, blocked | 3 | 3 | 33 | 343 |
186
- | …blocks that hold up when the text is read | 1, and 1 arguable | 1, and 1 arguable | 0 | 0 of 20 drawn at random |
187
- | 218 poisoned MCPTox tools on the held-out servers, blocked | 26 | 171 | 25 | 41 |
188
- | 225 MCPTox tools with an `<IMPORTANT>` or "Ignore the previous instructions" prefix, blocked | 225 | 225 | 222 | not run |
189
- | 45 clean MCPTox servers, blocked | 0 | 0 | 2 | 3 |
190
-
191
- - **Read the corpus row first.** No rule was fitted to it. mcp-audit's 33 blocks are 16 "homoglyphs" in text written wholly in its own script (Chinese punctuation, Greek symbols, Cyrillic), 12 honesty instructions such as "do not tell the user the check digits are wrong", 3 base64 utilities, an SSH public-key tool, and the deploy tool WARDEN also blocks by mistake. mcp-shield blocks 35% of real servers, almost all on a keyword: "API key", "token", `.env`, "..". An ellipsis ("Shopify...") counts as path traversal. It does block the identity service WARDEN blocks, on the word "credentials".
192
- - **Know which numbers are fitted.** We wrote the first attack set. Ruleset v9 was written after we had read both attack sets, and v10 after the 22 MCPTox servers of the other half. So 20 and 10 are the recall of rules fitted to what they were shown. The held-out MCPTox row, the clean servers, the corpus and the whole 0.8.2 column are not fitted. On the corpus v10 blocks exactly what v8 blocked.
193
- - **MCPTox tests a shape, not a keyword.** Almost every poisoned tool tells the model to call another tool first, or to change another tool's arguments. v10 names that shape (`TOOL_DEF_CROSS_TOOL`, see [the gate chain](gates.md)) and blocks 171 of 218 held-out tools, against 189 of 267 on the half it was written from. Add the benchmark's `<IMPORTANT>` or "Ignore the previous instructions" prefix and every scanner we ran catches it; we did not run mcp-shield on that set. On the clean servers mcp-audit blocks AmapMap and BaiduMap, and mcp-shield blocks FileSystem, AdFin and Commander on "sensitive file access".
194
- - **What WARDEN still misses:** 47 of the 218 held-out MCPTox tools, an instruction in Chinese to read `.env`, a paraphrase with no keyword ("gather every credential file … keep this step to yourself") and "include the output of env". It reports 41 of those 47, and all three of ours, as advisory, not as blocks. They need a meaning-based check, not another rule: with the optional classifier above, 191 of the 218 are blocked at `high` and all 218 are flagged.
195
- - **WARDEN is not alone in that slot.** mcp-audit also ships a lock file, a PR diff mode and SARIF.
193
+ On 2026-10-16 we ran WARDEN, mcp-audit 0.18.2 (`--connect`), mcp-shield 1.0.4, truecopy 0.10.4 and mcpsentry 0.1.5 over the same servers. Each server was replayed over stdio, so every scanner connected to it as it would in the field. Every scanner ran in a gVisor container with no network, from pinned images whose contents are hashed in a manifest. The harness, the sets, the manifest and every judgment are in [`scripts/scanner-comparison`](../scripts/scanner-comparison/). The full write-up, with the method and every caveat, is the [scanner comparison](scanner-comparison.md).
194
+
195
+ The MCPTox rows come from MCPTox (Wang et al., AAAI 2026), a published benchmark of 485 poisoned tools written for 45 real MCP servers. We split its servers in two by a fixed hash. Ruleset v10 was written from 22 servers; the table reports the other 23, with 218 poisoned tools no rule was fitted to. v11 and v12 were not written from them either, and give the same verdicts as v10.
196
+
197
+ | Servers | WARDEN 0.16.0 (v12) | mcp-audit 0.18.2 | mcp-shield 1.0.4 | truecopy 0.10.4 | mcpsentry 0.1.5 |
198
+ |---|---|---|---|---|---|
199
+ | 23 attacks we wrote, blocked | 20 | 10 | 6 | 8 | 4 |
200
+ | 10 attacks from mcp-audit's and mcp-shield's own fixtures, blocked | 10 | 10 | 8 | 7 | 5 |
201
+ | 12 hard benign cases, blocked | 0 | 1 | 1 | 1 | 2 |
202
+ | 218 poisoned MCPTox tools on the held-out servers, blocked | 171 | 25 | 41 | 27 | 8 |
203
+ | 225 MCPTox tools with an `<IMPORTANT>` or "Ignore the previous instructions" prefix, blocked | 225 | 222 | 41 | 141 | 136 |
204
+ | 45 clean MCPTox servers, blocked | 0 | 2 | 3 | 0 | 1 |
205
+ | 986 public servers, blocked | 3 | 33 | 343 | 39 | 86 |
206
+ | …blocks that hold up when the text is read | 1, and 1 arguable | 0 | 1 of the 34 we read | 1 | 0 |
207
+ | 14,933 npm and PyPI packages HISTOR observed, blocked | 369 | 928 | 5,354 | 252 | 1,449 |
208
+
209
+ - **Read the real-server rows first.** No rule was fitted to them. mcp-audit's 33 corpus blocks are mostly "homoglyphs" in text written wholly in its own script and honesty instructions such as "do not tell the user the check digits are wrong". mcp-shield blocks a third of real servers, almost all on a keyword: "API key", "token", `.env`, "..". truecopy blocks one vendor's docker-compose generators because they produce a `.env.example`. mcpsentry's base64 pattern matches any 40-character run of letters and slashes, which JSON Schema paths produce. On 14,933 npm and PyPI packages, a seeded sample of 996 where we judged every block has 23 WARDEN blocks, none of which holds up and 4 of which are arguable; mcp-shield blocks 339 of the same packages and mcpsentry 112.
210
+ - **Know which numbers are fitted.** We wrote the first attack set, and ruleset v9 was written after we had read both attack sets. The held-out MCPTox row, the clean servers, the corpus and the packages are not fitted.
211
+ - **MCPTox tests a shape, not a keyword.** Almost every poisoned tool tells the model to call another tool first, or to change another tool's arguments. v10 named that shape (`TOOL_DEF_CROSS_TOOL`, see [the gate chain](gates.md)) and v12 keeps it. Add the benchmark's `<IMPORTANT>` prefix and most scanners catch most tools.
212
+ - **What WARDEN still misses:** 47 of the 218 held-out MCPTox tools, an instruction in Chinese to read `.env`, a paraphrase with no keyword ("gather every credential file … keep this step to yourself") and "include the output of env". It reports 41 of those 47 as advisory, not as blocks. With the optional classifier above all 218 are flagged at `high`.
213
+ - **WARDEN is not alone in that slot.** mcp-audit also ships a lock file, a PR diff mode and SARIF; truecopy pins and signs definitions in a lock file too.
196
214
 
197
215
  ## What scan does not do
198
216