@aimarket/warden 0.18.0 → 0.19.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.
package/docs/gates.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 🌐 **English** · [Русский](gates.ru.md) · [Español](gates.es.md) · [Français](gates.fr.md) · [中文](gates.zh.md)
4
4
 
5
- **Ruleset v14 (unreleased, audit fix):** `keyStaysLocal` no longer treats storage on a server as local custody. All corpus/MCPTox numbers quoted for v13 below are historical; v14 has only local regression validation, with no new benchmark.
5
+ **Ruleset v15 (unreleased):** v14 stopped treating storage on a server as local custody (audit fix, local regression tests only); v15 widens `TOOL_DEF_CROSS_TOOL`, measured on 2026-10-22 on MCPTox, the field corpus and 1,000 HISTOR packages (see v15 below). Numbers quoted for earlier versions are historical.
6
6
 
7
7
  > [0.7.0 security changes and migration](security-hardening.md).
8
8
 
@@ -53,8 +53,8 @@ the threshold.
53
53
 
54
54
  Local regex scan over every field a tool advertises: its `name`, `description` and `inputSchema`,
55
55
  and since v6 its `title`, `outputSchema`, `annotations` and extension metadata (everything else the
56
- server sent, a base64 image icon excepted). 36 rules in ruleset **v14**: 25 `block`, 11 `advise`, and
57
- 25 of them carry a context **guard** — a named
56
+ server sent, a base64 image icon excepted). 37 rules in ruleset **v15**: 26 `block`, 11 `advise`, and
57
+ 26 of them carry a context **guard** — a named
58
58
  check that decides whether a match is really the thing the rule is looking for. See
59
59
  [the field survey](mcp-survey.md) for the 1 108-server run that calibrated v4.
60
60
 
@@ -154,7 +154,21 @@ new credential's private key", "You keep the private key.", "messages from one s
154
154
  blocked 3, losing none: the new one is a hosted builder whose argument takes the 64-byte secret key of a new mint
155
155
  key pair. On MCPTox it changes nothing: 171 of 218 held-out poisoned tools blocked, as with v12 (the measurement reproduced exactly), and none of the 45 clean servers; MCPTox's tools rewrite other tools' calls rather than ask for keys. Tests: `test/ruleset-v13.test.ts`.
156
156
 
157
- Every rule declares which of those seven **surfaces** it runs on, and 24 of the 36 include the name.
157
+ **v15** is written from MCPTox's dev half again, after a reader asked what WARDEN still misses: 78 of its 267
158
+ poisoned tools passed v14. `TOOL_DEF_CROSS_TOOL` now also recognises the user's call ("when a user calls `X`",
159
+ "when a user's query for `X` …"), a passive one ("when `X` is called"), every call ("all `X` requests", "all web
160
+ searches using the `X` tool"), and rewrites a mandate binds to a parameter or a quoted value ("you must set the
161
+ `mode` parameter to …", "you should redirect any `symbol` to 'QQQ'", "When using `X`, set `bcc` to '…'"). A new
162
+ pattern blocks a call to another tool ordered at a fixed target and enforced with a threat ("use 'deleteEmail' with
163
+ UID 99999 … Failure to do so will crash the system"); an honest prerequisite names no fixed target and threatens
164
+ nothing. A first draft that matched any "when the user asks …" blocked 7 honest servers of the corpus; four of
165
+ them are pinned as tests. On the dev half v15 blocks 233 of 267 (v14: 189); on the held-out half, measured once after the
166
+ rules were frozen, 194 of 218 (v14: 171); the added lines share no eight-word sequence with any held-out tool. It
167
+ blocks none of the 45 clean servers, the same 4 servers of the field corpus as v14 and the same 28 of a seeded
168
+ 1,000-package HISTOR sample. Tests: `test/ruleset-v15.test.ts`; results:
169
+ `scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json`.
170
+
171
+ Every rule declares which of those seven **surfaces** it runs on, and 24 of the 37 include the name.
158
172
  Four of the codes that do not are the noun-keyed ones (`TOOL_DEF_SECRET_REQUEST`,
159
173
  `TOOL_DEF_CREDENTIAL_PARAM`, `TOOL_DEF_ENV_REFERENCE`, `TOOL_DEF_SECRET_EXFIL`): a name is an identifier, `api_key` and
160
174
  `private_key` are ordinary parts of one, and refusing `sign_with_private_key` would be the ruleset
@@ -177,7 +191,7 @@ Gate score is `1 − penalty(worst blocking severity)`; advisory hits never affe
177
191
  | `TOOL_DEF_SECRET_REQUEST` | critical | block | — | `private_key`, `seed_phrase`/`mnemonic`, `~/.ssh` paths |
178
192
  | `TOOL_DEF_SECRET_HARVEST` | critical | block | ✅ | a tool whose stated job is to read/dump/reveal secrets, including from `~/.aws/credentials`, `~/.kube/config` and other credential stores |
179
193
  | `TOOL_DEF_EXFIL` | critical / high | block | ✅ | "post to https://…", "send a copy of all messages to <mailbox>", `bcc <mailbox>`, the conversation sent out with an address, credential or concealment, "exfiltrate", upload-to-host phrasing |
180
- | `TOOL_DEF_CROSS_TOOL` | high | block | — | a tool's text binding to another tool's call to rewrite its input or pre-empt it with a third call; a no-input tool that only orders another call |
194
+ | `TOOL_DEF_CROSS_TOOL` | high | block | — | a tool's text binding to another tool's call to rewrite its input or pre-empt it with a third call; a no-input tool that only orders another call; a call to another tool at a fixed target, enforced with a threat (v15) |
181
195
  | `TOOL_DEF_HIDDEN_UNICODE` | high | block | ✅ | zero-width, bidi control and isolate characters, and the Unicode-tag block — text the reviewer cannot see |
182
196
  | `TOOL_DEF_BASE64_BLOB` | high | block | ✅ | a 120+ character base64 run in a name, description or schema |
183
197
  | `TOOL_DEF_DATA_URL` | high | block | ✅ | `data:…;base64,` and `javascript:` URLs |
package/docs/gates.ru.md CHANGED
@@ -2,7 +2,7 @@
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 выполнены только локальные регрессионные тесты, новых прогонов нет.
5
+ **Ruleset v15 (не выпущен):** v14 перестал принимать хранение на сервере за хранение у пользователя (исправление аудита, только локальные регрессионные тесты); v15 расширяет `TOOL_DEF_CROSS_TOOL` и измерен 2026-10-22 на MCPTox, полевом корпусе и 1 000 пакетов HISTOR (см. v15 ниже). Цифры для прежних версий — исторические.
6
6
 
7
7
  > [Изменения безопасности 0.7.0 и миграция](security-hardening.ru.md).
8
8
 
@@ -54,8 +54,8 @@ Severity отвечает на вопрос *сколько внимания э
54
54
 
55
55
  Локальное regex-сканирование всех полей, которые объявляет инструмент: `name`, `description` и
56
56
  `inputSchema`, а начиная с v6 ещё `title`, `outputSchema`, `annotations` и метаданные расширений (всё
57
- остальное, что прислал сервер, кроме иконки-изображения в base64). 36 правил в наборе **v14**: 25
58
- `block`, 11 `advise`, и у 25 из них есть контекстный **guard** — именованная проверка, решающая,
57
+ остальное, что прислал сервер, кроме иконки-изображения в base64). 37 правил в наборе **v15**: 26
58
+ `block`, 11 `advise`, и у 26 из них есть контекстный **guard** — именованная проверка, решающая,
59
59
  действительно ли совпадение — то, что правило ищет. См.
60
60
  [полевой обзор](mcp-survey.ru.md) — прогон по 1 108 серверам, на котором калибровался v4.
61
61
 
@@ -158,7 +158,21 @@ the private key» по-прежнему блокируется). На корпу
158
158
  новый — удалённый сборщик, чей аргумент принимает 64-байтный секретный ключ новой пары ключей минта. На MCPTox ничего не меняется: 171 из 218 отравленных инструментов отложенной половины заблокированы, как и у v12 (замер воспроизвёлся точно), и ни один из 45 чистых серверов; инструменты MCPTox переписывают чужие вызовы, а не просят ключи.
159
159
  Тесты: `test/ruleset-v13.test.ts`.
160
160
 
161
- Каждое правило объявляет, на каких из этих семи **поверхностей** оно работает; 24 из 36 включают
161
+ **v15** снова написан по dev-половине MCPTox после вопроса читателя, чего WARDEN всё ещё не ловит: 78 из 267
162
+ отравленных инструментов проходили v14. `TOOL_DEF_CROSS_TOOL` теперь узнаёт и вызов пользователя («when a user calls
163
+ `X`», «when a user's query for `X` …»), и пассивный («when `X` is called»), и любой вызов («all `X` requests», «all
164
+ web searches using the `X` tool»), а также переписывание, которое предписание привязывает к параметру или к
165
+ значению в кавычках («you must set the `mode` parameter to …», «you should redirect any `symbol` to 'QQQ'», «When
166
+ using `X`, set `bcc` to '…'»). Новый шаблон блокирует вызов другого инструмента с фиксированной целью, подкреплённый
167
+ угрозой («use 'deleteEmail' with UID 99999 … Failure to do so will crash the system»); честное предварительное
168
+ условие не называет фиксированной цели и ничем не грозит. Первый вариант, ловивший любое «when the user asks …»,
169
+ блокировал 7 честных серверов корпуса; 4 из них закреплены в тестах. На dev-половине v15 блокирует 233 из 267 (v14 — 189);
170
+ на отложенной половине, измеренной один раз после заморозки правил, — 194 из 218 (v14 — 171); добавленные строки не
171
+ делят ни одной последовательности из восьми слов ни с одним отложенным инструментом. Он не блокирует ни одного из 45
172
+ чистых серверов, на полевом корпусе — те же 4 сервера, что и v14, и те же 28 из 1 000 пакетов HISTOR. Тесты:
173
+ `test/ruleset-v15.test.ts`; результаты: `scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json`.
174
+
175
+ Каждое правило объявляет, на каких из этих семи **поверхностей** оно работает; 24 из 37 включают
162
176
  имя. Четыре кода из тех, что не включают имя, — это правила, завязанные на существительное
163
177
  (`TOOL_DEF_SECRET_REQUEST`, `TOOL_DEF_CREDENTIAL_PARAM`, `TOOL_DEF_ENV_REFERENCE`, `TOOL_DEF_SECRET_EXFIL`): имя — это
164
178
  идентификатор, `api_key` и `private_key` — его обычные части, и блокировать
@@ -181,7 +195,7 @@ base64-блоб в первом поле, которое читает модел
181
195
  | `TOOL_DEF_SECRET_REQUEST` | critical | block | — | `private_key`, `seed_phrase`/`mnemonic`, пути `~/.ssh` |
182
196
  | `TOOL_DEF_SECRET_HARVEST` | critical | block | ✅ | инструмент, чья заявленная задача — читать/выгружать/раскрывать секреты, в том числе из `~/.aws/credentials`, `~/.kube/config` и других хранилищ учётных данных |
183
197
  | `TOOL_DEF_EXFIL` | critical / high | block | ✅ | «post to https://…», «send a copy of all messages to <ящик>», `bcc <ящик>`, передача разговора вместе с адресом, учётными данными или сокрытием, «exfiltrate», формулировки про upload на хост |
184
- | `TOOL_DEF_CROSS_TOOL` | high | block | — | текст инструмента привязывается к вызову другого инструмента, чтобы переписать его вход или опередить его вызовом третьего; инструмент без входа, который только велит вызвать другой |
198
+ | `TOOL_DEF_CROSS_TOOL` | high | block | — | текст инструмента привязывается к вызову другого инструмента, чтобы переписать его вход или опередить его вызовом третьего; инструмент без входа, который только велит вызвать другой; вызов другого инструмента с фиксированной целью, подкреплённый угрозой (v15) |
185
199
  | `TOOL_DEF_HIDDEN_UNICODE` | high | block | ✅ | zero-width и bidi-управляющие символы — текст, которого рецензент не видит |
186
200
  | `TOOL_DEF_BASE64_BLOB` | high | block | ✅ | цепочка base64 от 120 символов в имени, описании или схеме |
187
201
  | `TOOL_DEF_DATA_URL` | high | block | ✅ | URL вида `data:…;base64,` и `javascript:` |
package/docs/gates.zh.md CHANGED
@@ -2,7 +2,7 @@
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 只进行了本地回归测试,没有新基准。
5
+ **Ruleset v15(尚未发布):** v14 不再把服务器存储视为本地保管(审计修复,只有本地回归测试);v15 扩展了 `TOOL_DEF_CROSS_TOOL`,于 2026-10-22 在 MCPTox、实地语料和 1,000 个 HISTOR 包上测量(见下文 v15)。早期版本的数字均为历史结果。
6
6
 
7
7
  > [0.7.0 安全更新与迁移](security-hardening.zh.md).
8
8
 
@@ -46,7 +46,7 @@ const SEVERITY_RANK = { info: 0, low: 1, medium: 2, high: 3, critical: 4 };
46
46
 
47
47
  ## static-scan
48
48
 
49
- 对工具公布的每个字段做本地正则扫描:`name`、`description` 与 `inputSchema`,以及自 v6 起的 `title`、`outputSchema`、`annotations` 和扩展元数据(服务器发来的其他一切内容,base64 图片图标除外)。规则集 **v14** 共 36 条规则:25 条 `block`,11 条 `advise`,其中 25 条带有上下文 **guard**——一项具名检查,用于判断某次命中是否真是该规则要找的东西。参见[实地普查](mcp-survey.zh.md),即校准 v4 的 1 108 台服务器实测。
49
+ 对工具公布的每个字段做本地正则扫描:`name`、`description` 与 `inputSchema`,以及自 v6 起的 `title`、`outputSchema`、`annotations` 和扩展元数据(服务器发来的其他一切内容,base64 图片图标除外)。规则集 **v15** 共 37 条规则:26 条 `block`,11 条 `advise`,其中 26 条带有上下文 **guard**——一项具名检查,用于判断某次命中是否真是该规则要找的东西。参见[实地普查](mcp-survey.zh.md),即校准 v4 的 1 108 台服务器实测。
50
50
 
51
51
  **v5:任何规则读取文本之前,先对文本做归一化。** NFKC 把全角字母、连字和其他兼容形式变成普通字母;单词内部的不可见字符被删除;Unicode 标签区块(ASCII 的不可见副本,能藏下一整句话)被解码;在拉丁字母与西里尔或希腊字母混写的单词里,形近字母被换成拉丁字母,而整词只用一种文字写成的单词保持不变。于是,无论周围文本是什么语言,英文规则都不能再被全角字母、词内零宽空格、标签字符或西里尔字母 `о` 绕过。归一化以 `fold` 的形式与规则一起发布,并计入 digest。两条隐藏载荷规则读取**原始**文本(`raw: true`)。
52
52
 
@@ -73,7 +73,9 @@ v13 把单词边缘的句点或连字符当作标点。这暴露了此前被同
73
73
  “You keep the private key.”“messages from one signing key”);guard `keyStaysLocal` 放过用于签名或由用户保留的密钥,除非同一分句里有任何东西把它移走(“sign it and paste the private key” 仍会被阻止)。
74
74
  在已提交的语料上,v13 阻止 4 台服务器,v12 是 3 台,且一台都没丢:新增的是一个托管构建器,它的参数接收一个新铸币密钥对的 64 字节私钥。在 MCPTox 上没有任何变化:留出一半的 218 个投毒工具中阻止 171 个,与 v12 相同(测量结果完全复现),45 台干净服务器一台都没阻止;MCPTox 的工具改写的是其他工具的调用,而不是索要密钥。测试:`test/ruleset-v13.test.ts`。
75
75
 
76
- 每条规则都声明自己在这七个**面**中的哪些上运行,36 条里有 24 条包含名称。不包含名称的代码中,有四个是以**名词**为
76
+ **v15** 再次依据 MCPTox 的 dev 一半编写,起因是一位读者问 WARDEN 还抓不到什么:267 个投毒工具中有 78 个能通过 v14。`TOOL_DEF_CROSS_TOOL` 现在还能识别用户的调用("when a user calls `X`"、"when a user's query for `X` …")、被动的说法("when `X` is called")、针对每一次调用的说法("all `X` requests"、"all web searches using the `X` tool"),以及由强制措辞绑定到某个参数或带引号的值上的改写("you must set the `mode` parameter to …"、"you should redirect any `symbol` to 'QQQ'"、"When using `X`, set `bcc` to '…'")。一个新模式拦截这样的定义:要求以固定目标调用另一个工具,并以威胁来强制("use 'deleteEmail' with UID 99999 … Failure to do so will crash the system");诚实的前置步骤既不指定固定目标,也不威胁什么。最初的草稿匹配任何"when the user asks …",结果拦下了语料库中 7 台诚实服务器;其中 4 台已作为测试固定下来。在 dev 一半上 v15 拦截 267 中 233 个(v14:189);在留出的一半上——规则冻结后只测一次——218 中 194 个(v14:171);新增的行与任何留出工具都没有共同的八词序列。它不拦截 45 台干净服务器中的任何一台,在实地语料上拦截的仍是 v14 的那 4 台,在 1,000 个 HISTOR 包的种子样本中拦截的仍是同样的 28 个。测试:`test/ruleset-v15.test.ts`;结果:`scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json`。
77
+
78
+ 每条规则都声明自己在这七个**面**中的哪些上运行,37 条里有 24 条包含名称。不包含名称的代码中,有四个是以**名词**为
77
79
  锚的规则(`TOOL_DEF_SECRET_REQUEST`、`TOOL_DEF_CREDENTIAL_PARAM`、`TOOL_DEF_ENV_REFERENCE`、`TOOL_DEF_SECRET_EXFIL`):名称是标识
78
80
  符,`api_key` 和 `private_key` 是标识符里再普通不过的组成部分,而拒绝 `sign_with_private_key` 等于把 v1 的
79
81
  校准错误换个面重犯一次。以**短语**为锚的规则需要空白字符,因此根本无法匹配 `snake_case`;而两条隐藏载荷规则
@@ -94,7 +96,7 @@ v13 把单词边缘的句点或连字符当作标点。这暴露了此前被同
94
96
  | `TOOL_DEF_SECRET_REQUEST` | critical | block | — | `private_key`、`seed_phrase`/`mnemonic`、`~/.ssh` 路径 |
95
97
  | `TOOL_DEF_SECRET_HARVEST` | critical | block | ✅ | 自称职责就是读取/导出/披露密钥的工具,包括从 `~/.aws/credentials`、`~/.kube/config` 等凭据存储中读取 |
96
98
  | `TOOL_DEF_EXFIL` | critical / high | block | ✅ | 「post to https://…」「send a copy of all messages to <邮箱>」、`bcc <邮箱>`、连同地址、凭据或隐瞒一起发出对话、「exfiltrate」、上传到某主机的措辞 |
97
- | `TOOL_DEF_CROSS_TOOL` | high | block | — | 工具文本绑定到另一个工具的调用上,以改写其输入或抢先调用第三个工具;没有输入、只要求调用另一个工具的工具 |
99
+ | `TOOL_DEF_CROSS_TOOL` | high | block | — | 工具文本绑定到另一个工具的调用上,以改写其输入或抢先调用第三个工具;没有输入、只要求调用另一个工具的工具;以固定目标调用另一个工具并以威胁强制(v15) |
98
100
  | `TOOL_DEF_HIDDEN_UNICODE` | high | block | ✅ | 零宽字符与双向控制字符——审阅者看不见的文本 |
99
101
  | `TOOL_DEF_BASE64_BLOB` | high | block | ✅ | 名称、描述或 schema 里长达 120+ 字符的 base64 串 |
100
102
  | `TOOL_DEF_DATA_URL` | high | block | ✅ | `data:…;base64,` 与 `javascript:` 形式的 URL |
@@ -57,6 +57,28 @@ Bloqueados, de:
57
57
  WARDEN incluido, corrió en un contenedor gVisor sin red en dos de nuestros servidores, desde imágenes cuyo
58
58
  contenido fijamos y resumimos con hashes. Véase [cómo se ejecutó](#cómo-se-ejecutó).
59
59
 
60
+ ## Ruleset v15, 2026-10-22 (solo WARDEN)
61
+
62
+ Un lector preguntó qué sigue sin detectar WARDEN. 78 de las 267 herramientas envenenadas de la mitad dev de MCPTox
63
+ pasaban v14, así que v15 amplía `TOOL_DEF_CROSS_TOOL` a partir de ellas y de nada más ([la regla](gates.es.md)). La
64
+ mitad reservada se midió una sola vez, tras congelar las reglas, y las líneas añadidas no comparten ninguna
65
+ secuencia de ocho palabras con ninguna herramienta reservada.
66
+
67
+ | | v14 | v15 |
68
+ |---|---|---|
69
+ | mitad dev de MCPTox (de la que salen las reglas) | 189 de 267 | 233 de 267 |
70
+ | **mitad reservada de MCPTox** | **171 de 218** | **194 de 218** |
71
+ | …secuestro de función con disparador explícito | 17 de 23 | 17 de 23 |
72
+ | …secuestro de función con disparador implícito | 59 de 66 | 61 de 66 |
73
+ | …manipulación de parámetros con disparador implícito | 95 de 129 | 116 de 129 |
74
+ | 45 servidores limpios de MCPTox | 0 | 0 |
75
+ | corpus de campo, 999 servidores con herramientas | 4 | los mismos 4 |
76
+ | paquetes de HISTOR, muestra con semilla de 1000 del listado del 2026-10-22 | 28 | los mismos 28 |
77
+
78
+ Los otros escáneres no se volvieron a ejecutar; la tabla del principio es del 2026-10-16. Se ejecutó en una
79
+ estación de trabajo, no en los contenedores gVisor del 2026-10-16. Veredictos por id de caso:
80
+ [`results/2026-10-22-mcptox-v15.json`](../scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json).
81
+
60
82
  ## Cinco escáneres, y los que no ejecutamos
61
83
 
62
84
  La ficha de WARDEN en Glama nombra siete herramientas relacionadas. Antes de decidir leímos el código o la ficha de
@@ -94,7 +116,7 @@ Cada servidor se reprodujo por stdio con un pequeño programa que responde a `in
94
116
  archivo JSON y no hace nada más. Cada escáner se conectó a él como lo haría con un servidor real, un servidor por
95
117
  ejecución, con su propio `HOME` vacío.
96
118
 
97
- - **Entradas fijas.** Antes de las ejecuciones escribimos un [manifiesto](../scripts/scanner-comparison/results/manifest-2026-10-16.json)
119
+ - **Entradas fijas.** Antes de las ejecuciones escribimos un [manifiesto](../scripts/scanner-comparison/results/manifest-2026-10-16.public.json)
98
120
  con el SHA-256 de cada archivo de entrada: 16 830 archivos en nueve conjuntos. Los archivos de reproducción eran
99
121
  de solo lectura para los escáneres.
100
122
  - **Herramientas fijas.** Una imagen para los otros cuatro escáneres y una para WARDEN, ambas sobre la misma base
@@ -57,6 +57,28 @@ Bloqués, sur :
57
57
  WARDEN compris, a tourné dans un conteneur gVisor sans réseau sur deux de nos serveurs, à partir d’images dont nous
58
58
  avons figé et haché le contenu. Voir [comment cela a tourné](#comment-cela-a-tourné).
59
59
 
60
+ ## Ruleset v15, 2026-10-22 (WARDEN seul)
61
+
62
+ Un lecteur a demandé ce que WARDEN ne repère toujours pas. 78 des 267 outils empoisonnés de la moitié dev de MCPTox
63
+ passaient v14 ; v15 élargit donc `TOOL_DEF_CROSS_TOOL` à partir d’eux, et de rien d’autre ([la règle](gates.fr.md)).
64
+ La moitié réservée a été mesurée une seule fois, après le gel des règles, et les lignes ajoutées ne partagent aucune
65
+ suite de huit mots avec un outil réservé.
66
+
67
+ | | v14 | v15 |
68
+ |---|---|---|
69
+ | moitié dev de MCPTox (source des règles) | 189 sur 267 | 233 sur 267 |
70
+ | **moitié réservée de MCPTox** | **171 sur 218** | **194 sur 218** |
71
+ | …détournement de fonction à déclencheur explicite | 17 sur 23 | 17 sur 23 |
72
+ | …détournement de fonction à déclencheur implicite | 59 sur 66 | 61 sur 66 |
73
+ | …altération de paramètres à déclencheur implicite | 95 sur 129 | 116 sur 129 |
74
+ | 45 serveurs MCPTox propres | 0 | 0 |
75
+ | corpus de terrain, 999 serveurs avec outils | 4 | les mêmes 4 |
76
+ | paquets HISTOR, échantillon de 1 000 à graine fixe tiré de la liste du 2026-10-22 | 28 | les mêmes 28 |
77
+
78
+ Les autres scanners n’ont pas été relancés ; le tableau du début date du 2026-10-16. L’exécution a eu lieu sur un
79
+ poste de travail, pas dans les conteneurs gVisor du 2026-10-16. Verdicts par identifiant de cas :
80
+ [`results/2026-10-22-mcptox-v15.json`](../scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json).
81
+
60
82
  ## Cinq scanners, et ceux que nous n’avons pas lancés
61
83
 
62
84
  La fiche de WARDEN sur Glama cite sept outils apparentés. Nous avons lu le code ou la fiche de chacun avant de
@@ -94,7 +116,7 @@ Chaque serveur a été rejoué en stdio par un petit programme qui répond à `i
94
116
  fichier JSON et ne fait rien d’autre. Chaque scanner s’y est connecté comme à un vrai serveur, un serveur par
95
117
  exécution, avec son propre `HOME` vide.
96
118
 
97
- - **Entrées figées.** Avant les exécutions, nous avons écrit un [manifeste](../scripts/scanner-comparison/results/manifest-2026-10-16.json)
119
+ - **Entrées figées.** Avant les exécutions, nous avons écrit un [manifeste](../scripts/scanner-comparison/results/manifest-2026-10-16.public.json)
98
120
  avec le SHA-256 de chaque fichier d’entrée : 16 830 fichiers dans neuf jeux. Les fichiers de rejeu étaient en
99
121
  lecture seule pour les scanners.
100
122
  - **Outils figés.** Une image pour les quatre autres scanners, une pour WARDEN, toutes deux sur la même base
@@ -53,6 +53,27 @@ Blocked, out of:
53
53
  ran in a gVisor container with no network on two of our servers, from images whose contents we pinned and
54
54
  hashed. See [how it was run](#how-it-was-run).
55
55
 
56
+ ## Ruleset v15, 2026-10-22 (WARDEN only)
57
+
58
+ A reader asked what WARDEN still misses. 78 of the 267 poisoned tools on MCPTox's dev half passed v14, so v15 widens
59
+ `TOOL_DEF_CROSS_TOOL` from those, and from nothing else ([the rule](gates.md)). The held-out half was measured
60
+ once, after the rules were frozen, and the added lines share no eight-word sequence with any held-out tool.
61
+
62
+ | | v14 | v15 |
63
+ |---|---|---|
64
+ | MCPTox dev half (rules written from it) | 189 of 267 | 233 of 267 |
65
+ | **MCPTox held-out half** | **171 of 218** | **194 of 218** |
66
+ | …explicit-trigger function hijacking | 17 of 23 | 17 of 23 |
67
+ | …implicit-trigger function hijacking | 59 of 66 | 61 of 66 |
68
+ | …implicit-trigger parameter tampering | 95 of 129 | 116 of 129 |
69
+ | 45 clean MCPTox servers | 0 | 0 |
70
+ | field corpus, 999 servers with tools | 4 | the same 4 |
71
+ | HISTOR packages, seeded sample of 1,000 drawn from the 2026-10-22 listing | 28 | the same 28 |
72
+
73
+ The other scanners were not run again; the table at the top is from 2026-10-16. The run was on a workstation, not
74
+ in the gVisor containers of 2026-10-16. Verdicts by case id:
75
+ [`results/2026-10-22-mcptox-v15.json`](../scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json).
76
+
56
77
  ## Five scanners, and the ones we did not run
57
78
 
58
79
  Glama's listing for WARDEN names seven related tools. We read each one's code or listing before deciding.
@@ -89,7 +110,7 @@ Every server was replayed over stdio by a small program that answers `initialize
89
110
  file and does nothing else. Each scanner connected to it as it would to a real server, one server per run, with
90
111
  its own empty `HOME`.
91
112
 
92
- - **Fixed inputs.** Before the runs we wrote a [manifest](../scripts/scanner-comparison/results/manifest-2026-10-16.json)
113
+ - **Fixed inputs.** Before the runs we wrote a [manifest](../scripts/scanner-comparison/results/manifest-2026-10-16.public.json)
93
114
  with the SHA-256 of every input file: 16,830 files in nine sets. The replay files were read-only to
94
115
  the scanners.
95
116
  - **Fixed tools.** One image for the four other scanners, one for WARDEN, both on the same `node:22-alpine` base.
@@ -57,6 +57,28 @@
57
57
  работал в контейнере gVisor без сети на двух наших серверах, из образов, содержимое которых мы закрепили и
58
58
  захешировали. См. [как шёл прогон](#как-шёл-прогон).
59
59
 
60
+ ## Ruleset v15, 2026-10-22 (только WARDEN)
61
+
62
+ Читатель спросил, чего WARDEN всё ещё не ловит. 78 из 267 отравленных инструментов dev-половины MCPTox проходили
63
+ v14, поэтому v15 расширяет `TOOL_DEF_CROSS_TOOL` по ним и только по ним ([правило](gates.ru.md)). Отложенную половину
64
+ измерили один раз, после заморозки правил; добавленные строки не делят ни одной последовательности из восьми слов
65
+ ни с одним отложенным инструментом.
66
+
67
+ | | v14 | v15 |
68
+ |---|---|---|
69
+ | dev-половина MCPTox (по ней писали правила) | 189 из 267 | 233 из 267 |
70
+ | **отложенная половина MCPTox** | **171 из 218** | **194 из 218** |
71
+ | …явный триггер, перехват функции | 17 из 23 | 17 из 23 |
72
+ | …неявный триггер, перехват функции | 59 из 66 | 61 из 66 |
73
+ | …неявный триггер, подмена параметров | 95 из 129 | 116 из 129 |
74
+ | 45 чистых серверов MCPTox | 0 | 0 |
75
+ | полевой корпус, 999 серверов с инструментами | 4 | те же 4 |
76
+ | пакеты HISTOR, выборка 1 000 с фиксированным зерном из списка на 2026-10-22 | 28 | те же 28 |
77
+
78
+ Другие сканеры заново не запускали; таблица в начале — от 2026-10-16. Прогон шёл на рабочей машине, а не в
79
+ контейнерах gVisor, как 2026-10-16. Вердикты по id случаев:
80
+ [`results/2026-10-22-mcptox-v15.json`](../scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json).
81
+
60
82
  ## Пять сканеров и те, что мы не запускали
61
83
 
62
84
  Страница WARDEN на Glama называет семь родственных инструментов. Прежде чем решать, мы прочитали код или страницу
@@ -94,7 +116,7 @@ Glama также показывает yotta-verify-mcp. Он сканирует
94
116
  JSON-файла и больше ничего не делает. Каждый сканер подключался к ней так же, как к настоящему серверу, по одному
95
117
  серверу на запуск, со своим пустым `HOME`.
96
118
 
97
- - **Закреплённые входы.** До прогонов мы записали [манифест](../scripts/scanner-comparison/results/manifest-2026-10-16.json)
119
+ - **Закреплённые входы.** До прогонов мы записали [манифест](../scripts/scanner-comparison/results/manifest-2026-10-16.public.json)
98
120
  с SHA-256 каждого входного файла: 16 830 файлов в девяти наборах. Файлы воспроизведения были доступны сканерам
99
121
  только на чтение.
100
122
  - **Закреплённые инструменты.** Один образ для четырёх других сканеров, один для WARDEN, оба на одной базе
@@ -51,6 +51,23 @@
51
51
  - **运行地点。** 10 月 9 日扫描器运行在一台工作站上。这一次,包括 WARDEN 在内的每款扫描器都在我们两台服务器上
52
52
  的无网络 gVisor 容器中运行,镜像内容经过固定并做了哈希。见[运行方式](#运行方式)。
53
53
 
54
+ ## 规则集 v15,2026-10-22(仅 WARDEN)
55
+
56
+ 一位读者问 WARDEN 还抓不到什么。MCPTox dev 一半的 267 个投毒工具中有 78 个能通过 v14,因此 v15 依据这些工具、且只依据它们扩展了 `TOOL_DEF_CROSS_TOOL`([规则](gates.zh.md))。留出的一半在规则冻结后只测量了一次,新增的行与任何留出工具都没有共同的八词序列。
57
+
58
+ | | v14 | v15 |
59
+ |---|---|---|
60
+ | MCPTox dev 一半(规则依据它编写) | 267 中 189 | 267 中 233 |
61
+ | **MCPTox 留出的一半** | **218 中 171** | **218 中 194** |
62
+ | …显式触发的函数劫持 | 23 中 17 | 23 中 17 |
63
+ | …隐式触发的函数劫持 | 66 中 59 | 66 中 61 |
64
+ | …隐式触发的参数篡改 | 129 中 95 | 129 中 116 |
65
+ | 45 台干净的 MCPTox 服务器 | 0 | 0 |
66
+ | 实地语料,999 台带工具的服务器 | 4 | 同样的 4 台 |
67
+ | HISTOR 包,从 2026-10-22 列表中按固定种子抽取的 1,000 个 | 28 | 同样的 28 个 |
68
+
69
+ 其他扫描器没有重新运行;开头的表格来自 2026-10-16。本次在一台工作站上运行,而不是 2026-10-16 的 gVisor 容器中。按用例 id 的判定:[`results/2026-10-22-mcptox-v15.json`](../scripts/scanner-comparison/results/2026-10-22-mcptox-v15.json)。
70
+
54
71
  ## 五款扫描器,以及我们没有运行的那些
55
72
 
56
73
  Glama 上 WARDEN 的页面列出了七款相关工具。我们在决定前读了每一款的代码或页面。
@@ -84,7 +101,7 @@ mcp-shield:`HIGH Risk` 的工具。truecopy:被其代理以 `poisoned` 拦
84
101
  每台服务器都通过 stdio 重放:一个小程序从 JSON 文件回答 `initialize` 和 `tools/list`,别的什么也不做。每款扫描器
85
102
  像连接真实服务器一样连接它,每次运行一台服务器,使用各自空的 `HOME`。
86
103
 
87
- - **固定的输入。** 运行前我们写了一份[清单](../scripts/scanner-comparison/results/manifest-2026-10-16.json),记录每个
104
+ - **固定的输入。** 运行前我们写了一份[清单](../scripts/scanner-comparison/results/manifest-2026-10-16.public.json),记录每个
88
105
  输入文件的 SHA-256:九个数据集共 16,830 个文件。重放文件对扫描器只读。
89
106
  - **固定的工具。** 一个镜像用于另外四款扫描器,一个用于 WARDEN,两者基于同一个 `node:22-alpine`。扫描器按上述版本
90
107
  取自 npm 和 PyPI,安装后的每个文件都与已发布的包一致,pip 自己改写的安装记录除外。WARDEN 来自被测提交的
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aimarket/warden",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "WARDEN — MCP security firewall. Stdio wrap proxy, inspection tools and library. Vets definitions before model exposure. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "license": "MIT",