@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/scan.ru.md CHANGED
@@ -146,6 +146,22 @@ Stdio-сервер, запущенный из публичного реестр
146
146
 
147
147
  Ответы HISTOR никогда не блокируют. Если HISTOR недоступен, это попадает в отчёт, а проверка продолжается.
148
148
 
149
+ ## Для издателей: заявите наборы инструментов своего сервера
150
+
151
+ HISTOR может записать только те инструменты, которые ваш сервер отдаёт в его песочнице. Если там, где установлено то, чего в песочнице нет, — раннер запускателя, по одному на ОС, настоящий ключ, — сервер отдаёт другие, заявите эти наборы, и те, кто их получает, увидят `HISTOR_DECLARED_TOOLSET` (low) вместо `HISTOR_UNSEEN_TOOLSET` (medium). На машине, которая получает набор:
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 запускает сервер так же, как клиент, считает дайджест его `tools/list` (MTL/1) и добавляет набор в `mcp-tool-sets.json`, сохраняя уже записанные наборы и заменяя тот же дайджест. Повторите на каждой ОС и версии раннера. Затем:
158
+
159
+ 1. Опубликуйте файл на домене, который реестр проверил для пространства имён вашего сервера, — `ai.acme/launcher` → `acme.ai` или поддомен; `io.github.<user>/…` → `<user>.github.io` или ваши raw-файлы на GitHub, — например по адресу `https://acme.ai/.well-known/mcp-tool-sets.json`.
160
+ 2. Один раз сошлитесь на него из записи в реестре: `npx -y @aimarket/warden declare --server-json --link <url>` печатает блок `_meta` для `server.json`; опубликуйте эту версию в реестре.
161
+ 3. Проверьте: `npx -y @aimarket/warden declare --check <url> --name ai.acme/launcher` читает файл так же, как прочтёт HISTOR, и говорит, что HISTOR из него возьмёт.
162
+
163
+ Дальше для выпуска раннера нужны только `declare --out` и повторная загрузка файла: HISTOR перечитывает его каждый час. Набор, который вы убрали из файла, отзывается; файл, который HISTOR не смог прочитать, сохраняет заявленное. Без файла `--server-json` с сервером после `--` кладёт набор прямо в запись, до 8 наборов. Правила, которые применяет HISTOR: [заявленные наборы](https://github.com/alexar76/histor/blob/main/docs/api.ru.md). Заявление — слово издателя, а не наблюдение: WARDEN по-прежнему выполняет все проверки над инструментами, которые получил.
164
+
149
165
  ## Необязательный классификатор
150
166
 
151
167
  Правила WARDEN работают офлайн и детерминированно, и они пропускают то, что не названо ни одним правилом: перефразировку, инструкцию на другом языке. `--classifier-url` и `--classifier-model` добавляют второе мнение модели, которую выбираете вы, через любой OpenAI-совместимый адрес: локальный Ollama, vLLM или LM Studio либо облачный API.
@@ -160,39 +176,41 @@ WARDEN_CLASSIFIER_API_KEY=… warden-mcp scan --classifier-url https://api.deeps
160
176
  - **Проверка полномочий на любом языке.** Пять категорий: `instruction_to_model`, `exfiltration`, `secret_request`, `concealment`, `cross_tool`. Промпт отличает требования самого инструмента от подмены указаний пользователя, выдуманного согласия и управления чужими инструментами. Случайные разделители не гарантируют защиту от инъекции. Протокол требует решение по каждому инструменту и ссылки на номера полей. WARDEN сам извлекает доказательства из исходника. Неполное решение повторно проверяется один раз отдельно; сбои API не размножают запросы.
161
177
  - **Проверка не даёт доверия.** Владение языками зависит от модели. Независимую от языка границу допуска даёт [`wrap --require-approval`](security-hardening-language-boundary.md); LLM не может выдать это утверждение. Старые ответы HISTOR остаются рекомендательными и используют прежний протокол.
162
178
 
163
- Замер 9 октября 2026 года на `deepseek-flash`, той же модели, что у HISTOR, на MCPTox (опубликованный бенчмарк, он описан в сравнении ниже) и на наших наборах:
179
+ Замер 16 октября 2026 года на `deepseek-flash`, той же модели, что у HISTOR, на MCPTox (опубликованный бенчмарк, он описан в сравнении ниже), на настоящих серверах и на наших наборах:
164
180
 
165
- | | Правила (v10) | Правила + классификатор, блокировка на `high` | Правила + любые пометки классификатора (рекомендательно) |
166
- |---|---|---|---|
167
- | Отложенная половина MCPTox, поймано из 218 отравленных инструментов | 171 | 191 | 218 |
168
- | 45 чистых серверов MCPTox, заблокировано или помечено | 0 | 0 | 4 помечено |
169
- | 200 случайных серверов корпуса, заблокировано или помечено | 2 заблокировано | 2 заблокировано | 2 заблокировано, ещё 12 помечено |
170
- | 23 наши атаки / 12 трудных безобидных случаев | 20 / 0 | 22 / 0 | 23 / 0 |
181
+ | | Правила (v12) | Правила + классификатор на `high` |
182
+ |---|---|---|
183
+ | Отложенная половина MCPTox, поймано из 218 отравленных инструментов | 171 | 218 |
184
+ | 45 чистых серверов MCPTox, помечено | 0 | 0 |
185
+ | 200 случайно выбранных серверов корпуса, заблокировано или помечено | 2 | 5 |
186
+ | 996 пакетов npm и PyPI из случайной выборки, заблокировано или помечено | 23 | 35 |
187
+ | 23 атаки, написанные нами / 12 трудных безобидных случаев | 20 / 0 | 23 / 0 |
171
188
 
172
- Два сервера, которые блокируют правила, — это сервис идентичности и деплой-инструмент из сравнения ниже. 13 серверов, помеченных классификатором, получили `medium` или `low`, ни одного `high`. Шесть из них стоит показать человеку: один велит модели провести необратимую передачу ENS-имени «первым и единственным действием», не спрашивая пользователя, другой велит не раскрывать, откуда его данные. Модель помечает и официальный сервер Fetch: его описание говорит модели, что у неё теперь есть интернет и отказываться не нужно. Это инструкция модели, но не атака. Модель пропустила то, что ловят правила: инъекцию в аннотациях, запрос приватного ключа или seed-фразы как параметра и `rm -rf ~`.
189
+ Два сервера корпуса, которые блокируют правила, — это сервис идентичности и инструмент развёртывания из сравнения ниже. Пометки классификатора `high` на настоящих серверах — в основном распоряжения о порядке работы вроде «сначала вызови этот инструмент». Два пакета стоит посмотреть человеку, и правила не блокируют ни один: один оборачивает описание в поддельный блок «пользователь сам это попросил» и велит модели вызывать его перед любым ответом; другой отправляет содержимое файлов от агента на свой сервер с «Do NOT display … to the user». Модель пропустила то, что ловят правила: инъекцию в имени инструмента, приватный ключ или seed-фразу, запрошенные как параметр, и `rm -rf ~`. Вместе они ловят все 23 наши атаки.
173
190
 
174
191
  ## Сравнение
175
192
 
176
- 9 октября 2026 года мы прогнали WARDEN, mcp-audit 0.18.2 (`--connect`) и mcp-shield 1.0.4 по одним и тем же серверам. Каждый сервер воспроизводился по stdio, так что каждый сканер подключался к нему так же, как в жизни. Стенд, наборы и разметка каждого случая лежат в [`scripts/scanner-comparison`](../scripts/scanner-comparison/). Полный разбор с методом и всеми оговорками — в [сравнении сканеров](scanner-comparison.ru.md).
177
-
178
- Последние три строки взяты из MCPTox (Wang et al., AAAI 2026) — опубликованного бенчмарка из 485 отравленных инструментов, написанных для 45 настоящих MCP-серверов. Мы разделили его серверы пополам по фиксированному хешу. Ruleset v10 написан по 22 серверам; в таблице — остальные 23, с 218 отравленными инструментами, под которые не подгонялось ни одно правило.
179
-
180
- | Серверы | WARDEN 0.8.2 (v8) | WARDEN 0.9.0 (v10) | mcp-audit 0.18.2 | mcp-shield 1.0.4 |
181
- |---|---|---|---|---|
182
- | 23 атаки, написанные нами, заблокировано | 14 | 20 | 10 | 6 |
183
- | 10 атак из фикстур самих mcp-audit и mcp-shield, заблокировано | 7 | 10 | 10 | 8 |
184
- | 12 трудных безобидных случаев, заблокировано | 0 | 0 | 1 | 1 |
185
- | 986 публичных серверов, заблокировано | 3 | 3 | 33 | 343 |
186
- | …из них по делу, если прочитать текст | 1 и 1 спорный | 1 и 1 спорный | 0 | 0 из 20 случайно выбранных |
187
- | 218 отравленных инструментов MCPTox на отложенных серверах, заблокировано | 26 | 171 | 25 | 41 |
188
- | 225 инструментов MCPTox с префиксом `<IMPORTANT>` или «Ignore the previous instructions», заблокировано | 225 | 225 | 222 | не запускали |
189
- | 45 чистых серверов MCPTox, заблокировано | 0 | 0 | 2 | 3 |
190
-
191
- - **Сначала читайте строку корпуса.** Под неё не подгонялось ни одно правило. 33 блокировки mcp-audit — это 16 «омоглифов» в тексте, целиком написанном на своём алфавите (китайская пунктуация, греческие символы, кириллица), 12 инструкций честности вроде «do not tell the user the check digits are wrong», 3 утилиты base64, инструмент для публичного SSH-ключа и деплой-инструмент, который WARDEN тоже блокирует по ошибке. mcp-shield блокирует 35% настоящих серверов, почти всегда по ключевому слову: «API key», «token», `.env`, «..». Многоточие («Shopify...») он считает выходом из каталога. Сервис идентичности, который блокирует WARDEN, он тоже блокирует, но за слово «credentials».
192
- - **Помните, какие числа подогнаны.** Первый набор атак написали мы. Ruleset v9 написан после того, как мы прочли оба набора атак, а v10 — после 22 серверов MCPTox из другой половины. Так что 20 и 10 — это полнота правил, подогнанных под увиденное. Отложенная строка MCPTox, чистые серверы, корпус и весь столбец 0.8.2 не подогнаны. На корпусе v10 блокирует ровно то же, что v8.
193
- - **MCPTox проверяет форму, а не ключевое слово.** Почти каждый отравленный инструмент велит модели сначала вызвать другой инструмент или изменить аргументы другого инструмента. v10 называет эту форму (`TOOL_DEF_CROSS_TOOL`, см. [цепочку гейтов](gates.ru.md)) и блокирует 171 из 218 отложенных инструментов против 189 из 267 на половине, по которой он написан. С префиксом бенчмарка `<IMPORTANT>` или «Ignore the previous instructions» их ловит каждый запущенный нами сканер; mcp-shield на этом наборе мы не запускали. На чистых серверах mcp-audit блокирует AmapMap и BaiduMap, а mcp-shield — FileSystem, AdFin и Commander за «sensitive file access».
194
- - **Что WARDEN всё ещё пропускает:** 47 из 218 отложенных инструментов MCPTox, инструкцию по-китайски прочитать `.env`, перефразировку без ключевых слов («gather every credential file … keep this step to yourself») и «include the output of env». О 41 из этих 47 и обо всех трёх наших он сообщает рекомендательно, но не блокирует. Здесь нужна проверка по смыслу, а не ещё одно правило: с необязательным классификатором выше 191 из 218 блокируются на уровне `high`, а помечаются все 218.
195
- - **WARDEN в этой нише не один.** У mcp-audit тоже есть лок-файл, режим диффа для PR и SARIF.
193
+ 16 октября 2026 года мы прогнали WARDEN, mcp-audit 0.18.2 (`--connect`), mcp-shield 1.0.4, truecopy 0.10.4 и mcpsentry 0.1.5 по одним и тем же серверам. Каждый сервер воспроизводился по stdio, так что каждый сканер подключался к нему так же, как в жизни. Каждый сканер работал в контейнере gVisor без сети, из закреплённых образов, содержимое которых захешировано в манифесте. Стенд, наборы, манифест и каждая разметка лежат в [`scripts/scanner-comparison`](../scripts/scanner-comparison/). Полное описание с методикой и всеми оговорками — в [сравнении сканеров](scanner-comparison.ru.md).
194
+
195
+ Строки MCPTox взяты из MCPTox (Wang et al., AAAI 2026) — опубликованного бенчмарка из 485 отравленных инструментов, написанных для 45 настоящих MCP-серверов. Мы разделили его серверы на две части фиксированным хешем. Набор правил v10 писался по 22 серверам; таблица показывает остальные 23, с 218 отравленными инструментами, под которые не подгонялось ни одно правило. v11 и v12 по ним тоже не писались и дают те же вердикты, что и v10.
196
+
197
+ | Серверы | 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 атаки, написанные нами, заблокировано | 20 | 10 | 6 | 8 | 4 |
200
+ | 10 атак из фикстур самих mcp-audit и mcp-shield, заблокировано | 10 | 10 | 8 | 7 | 5 |
201
+ | 12 трудных безобидных случаев, заблокировано | 0 | 1 | 1 | 1 | 2 |
202
+ | 218 отравленных инструментов MCPTox на отложенных серверах, заблокировано | 171 | 25 | 41 | 27 | 8 |
203
+ | 225 инструментов MCPTox с префиксом `<IMPORTANT>` или «Ignore the previous instructions», заблокировано | 225 | 222 | 41 | 141 | 136 |
204
+ | 45 чистых серверов MCPTox, заблокировано | 0 | 2 | 3 | 0 | 1 |
205
+ | 986 публичных серверов, заблокировано | 3 | 33 | 343 | 39 | 86 |
206
+ | …блокировок по делу, если прочитать текст | 1 и 1 спорная | 0 | 1 из 34 прочитанных | 1 | 0 |
207
+ | 14 933 пакета npm и PyPI, которые наблюдал HISTOR, заблокировано | 369 | 928 | 5 354 | 252 | 1 449 |
208
+
209
+ - **Сначала читайте строки с настоящими серверами.** Под них не подгонялось ни одно правило. 33 блокировки mcp-audit на корпусе — в основном «гомоглифы» в тексте, целиком написанном в своей письменности, и инструкции честности вроде «do not tell the user the check digits are wrong». mcp-shield блокирует треть настоящих серверов, почти всегда по ключевому слову: «API key», «token», `.env`, «..». truecopy блокирует генераторы docker-compose одного поставщика за то, что они выпускают `.env.example`. Шаблон base64 у mcpsentry совпадает с любой цепочкой из 40 букв и косых черт, какие дают пути JSON Schema. На 14 933 пакетах npm и PyPI в случайной выборке из 996, где мы разобрали каждую блокировку, у WARDEN 23 блокировки, ни одной по делу и 4 спорные; mcp-shield блокирует 339 из тех же пакетов, mcpsentry — 112.
210
+ - **Знайте, какие числа подогнаны.** Первый набор атак написали мы, а набор правил v9 писался после того, как мы прочитали оба набора атак. Строка отложенной половины MCPTox, чистые серверы, корпус и пакеты не подогнаны.
211
+ - **MCPTox проверяет форму, а не ключевое слово.** Почти каждый отравленный инструмент велит модели сначала вызвать другой инструмент или поменять его аргументы. v10 дал этой форме имя (`TOOL_DEF_CROSS_TOOL`, см. [цепочку гейтов](gates.ru.md)), v12 её сохраняет. С префиксом бенчмарка `<IMPORTANT>` большинство сканеров ловит большинство инструментов.
212
+ - **Что WARDEN всё ещё пропускает:** 47 из 218 отложенных инструментов MCPTox, инструкцию по-китайски прочитать `.env`, перефразировку без ключевых слов («gather every credential file … keep this step to yourself») и «include the output of env». О 41 из этих 47 он сообщает рекомендательно, а не блокирует. С необязательным классификатором выше все 218 помечаются на `high`.
213
+ - **WARDEN в этой нише не один.** У mcp-audit тоже есть лок-файл, режим диффа для PR и SARIF; truecopy тоже закрепляет и подписывает определения в лок-файле.
196
214
 
197
215
  ## Чего scan не делает
198
216
 
package/docs/scan.zh.md CHANGED
@@ -146,6 +146,22 @@ repos:
146
146
 
147
147
  HISTOR 的回答从不阻止。HISTOR 没有响应时会在报告中注明,扫描继续进行。
148
148
 
149
+ ## 面向发布者:声明你的服务器的工具集
150
+
151
+ HISTOR 只能记录你的服务器在其沙箱中列出的工具。如果在安装了沙箱所没有的东西的地方——启动器的运行器、每个操作系统各一个、真实的密钥——它列出的是别的工具,就声明这些工具集,拿到它们的人看到的将是 `HISTOR_DECLARED_TOOLSET`(low),而不是 `HISTOR_UNSEEN_TOOLSET`(medium)。在能拿到该工具集的机器上:
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 会像客户端一样启动服务器,计算其 `tools/list` 的摘要(MTL/1),并把该工具集加入 `mcp-tool-sets.json`,保留已有的工具集并替换相同的摘要。在每个操作系统和每个运行器版本上重复。然后:
158
+
159
+ 1. 把文件发布到注册表为你的服务器命名空间验证过的域名上——`ai.acme/launcher` → `acme.ai` 或其子域名;`io.github.<user>/…` → `<user>.github.io` 或你在 GitHub 上的 raw 文件——例如 `https://acme.ai/.well-known/mcp-tool-sets.json`。
160
+ 2. 让注册表条目指向它,只需一次:`npx -y @aimarket/warden declare --server-json --link <url>` 打印 `server.json` 的 `_meta` 块;把这个版本发布到注册表。
161
+ 3. 检查:`npx -y @aimarket/warden declare --check <url> --name ai.acme/launcher` 按 HISTOR 的方式读取文件,并说明 HISTOR 会从中采用什么。
162
+
163
+ 此后,发布新的运行器只需要 `declare --out` 并重新上传文件:HISTOR 每小时读取一次。从文件中删去的工具集会被撤回;HISTOR 无法读取的文件会保留其声明。不使用文件时,`--server-json` 加上 `--` 之后的服务器会把工具集直接放进条目,最多 8 个。HISTOR 采用的规则:[声明工具集](https://github.com/alexar76/histor/blob/main/docs/api.zh.md)。声明是发布者的说法,不是观测:WARDEN 仍会对拿到的工具执行全部检查。
164
+
149
165
  ## 可选的分类器
150
166
 
151
167
  WARDEN 的规则离线、确定性地运行,也会漏掉任何规则都没提到的内容:改写的说法、另一种语言的指令。`--classifier-url` 和 `--classifier-model` 通过任意 OpenAI 兼容端点,加入你所选模型的第二意见:本地的 Ollama、vLLM 或 LM Studio,或托管 API。
@@ -160,39 +176,41 @@ WARDEN_CLASSIFIER_API_KEY=… warden-mcp scan --classifier-url https://api.deeps
160
176
  - **五类语义检查。** `instruction_to_model`、`exfiltration`、`secret_request`、`concealment`、`cross_tool`。检查任何语言中的权限越界,但效果取决于模型的语言能力。协议要求每个工具有明确决定及有效的字段编号;WARDEN 自行从原文提取证据。每个未完成的工具最多单独重试一次。随机分隔符不保证免疫提示注入。
161
177
  - **检查不等于批准。** [`wrap --require-approval`](security-hardening-language-boundary.md) 提供独立于语言的操作员批准边界。HISTOR 的历史模型结果仍然仅供参考。
162
178
 
163
- 2026 年 10 月 9 日用 `deepseek-flash`(HISTOR 使用的同一模型)在 MCPTox(下文对比中介绍的公开基准)和我们自己的样本集上测得:
179
+ 2026 年 10 月 16 日用 `deepseek-flash`(HISTOR 使用的同一模型)在 MCPTox(下文对比中介绍的公开基准)、真实服务器和我们自己的样本集上测得:
164
180
 
165
- | | 规则(v10) | 规则 + 分类器,`high` 时阻止 | 规则 + 分类器的任何标记(仅作建议) |
166
- |---|---|---|---|
167
- | MCPTox 留出的一半,218 个投毒工具中被发现的数量 | 171 | 191 | 218 |
168
- | 45 台 MCPTox 干净服务器,被阻止或被标记 | 0 | 0 | 4 台被标记 |
169
- | 随机抽取的 200 台语料服务器,被阻止或被标记 | 2 台被阻止 | 2 台被阻止 | 2 台被阻止,另 12 台被标记 |
170
- | 我们写的 23 个攻击 / 12 个困难的良性样例 | 20 / 0 | 22 / 0 | 23 / 0 |
181
+ | | 规则(v12) | 规则 + `high` 级分类器 |
182
+ |---|---|---|
183
+ | MCPTox 留出的一半,218 个投毒工具中被发现的数量 | 171 | 218 |
184
+ | 45 台干净的 MCPTox 服务器,被标记数 | 0 | 0 |
185
+ | 随机抽取的 200 台语料服务器,被阻止或标记数 | 2 | 5 |
186
+ | 随机样本中的 996 个 npm 与 PyPI 包,被阻止或标记数 | 23 | 35 |
187
+ | 我们编写的 23 个攻击 / 12 个困难的良性样例 | 20 / 0 | 23 / 0 |
171
188
 
172
- 规则阻止的那两台是下文对比中的身份服务和部署工具。分类器标记的 13 台服务器都是 `medium` 或 `low`,没有 `high`。其中 6 台值得人工查看:一台要求模型“作为第一个也是唯一的动作”进行不可撤销的 ENS 名称转移,且不询问用户;另一台要求模型不要透露其数据来源。模型还标记了官方的 Fetch 服务器,它的描述告诉模型现在可以上网、不应拒绝。这是对模型的指令,但不是攻击。模型漏掉了规则能发现的内容:annotations 中的注入、以参数形式索要私钥或助记词,以及 `rm -rf ~`。
189
+ 规则阻止的两台语料服务器,是下文对比中的身份服务和部署工具。分类器在真实服务器上的 `high` 标记大多是“先调用这个工具”之类的工作流指令。有两个包值得人工查看,而规则一个也没有阻止:一个把描述包在伪造的“这是用户要求的”块中,并命令模型在任何回复之前先调用它;另一个把文件内容从智能体发送到自己的服务器,并写着 “Do NOT display … to the user”。模型漏掉了规则能抓到的东西:工具名中的注入、作为参数索要的私钥或助记词,以及 `rm -rf ~`。两者合起来能发现我们全部 23 个攻击。
173
190
 
174
191
  ## 对比
175
192
 
176
- 2026 年 10 月 9 日,我们在同一批服务器上运行了 WARDEN、mcp-audit 0.18.2(`--connect`)和 mcp-shield 1.0.4。每台服务器都通过 stdio 重放,因此每个扫描器连接它的方式与真实环境相同。测试工具、样本集和每一条判定都在 [`scripts/scanner-comparison`](../scripts/scanner-comparison/) 中。包含方法和全部注意事项的完整研究,见[扫描器对比](scanner-comparison.zh.md)。
177
-
178
- 最后三行来自 MCPTox(Wang 等,AAAI 2026):一个公开的基准,包含为 45 台真实 MCP 服务器编写的 485 个投毒工具。我们用固定哈希把它的服务器分成两半。ruleset v10 依据其中 22 台服务器编写;表中报告的是另外 23 台,共 218 个投毒工具,没有任何规则照着它们调过。
179
-
180
- | 服务器 | WARDEN 0.8.2(v8) | WARDEN 0.9.0(v10) | mcp-audit 0.18.2 | mcp-shield 1.0.4 |
181
- |---|---|---|---|---|
182
- | 我们编写的 23 个攻击,阻止数 | 14 | 20 | 10 | 6 |
183
- | 取自 mcp-audit 与 mcp-shield 自带样例的 10 个攻击,阻止数 | 7 | 10 | 10 | 8 |
184
- | 12 个困难的良性样例,阻止数 | 0 | 0 | 1 | 1 |
185
- | 986 台公开服务器,阻止数 | 3 | 3 | 33 | 343 |
186
- | …读过文本后站得住脚的阻止 | 1 台,另 1 台存疑 | 1 台,另 1 台存疑 | 0 | 随机抽取的 20 台中 0 台 |
187
- | MCPTox 留出服务器上的 218 个投毒工具,阻止数 | 26 | 171 | 25 | 41 |
188
- | 带 `<IMPORTANT>` 或 “Ignore the previous instructions” 前缀的 225 个 MCPTox 工具,阻止数 | 225 | 225 | 222 | 未运行 |
189
- | 45 台 MCPTox 干净服务器,阻止数 | 0 | 0 | 2 | 3 |
190
-
191
- - **先看语料这一行。** 没有任何规则是照着它调的。mcp-audit 的 33 次阻止中,16 次是对完全用本文字书写的文本报“同形字”(中文标点、希腊符号、西里尔字母),12 次是诚实性提示(如 “do not tell the user the check digits are wrong”),3 次是 base64 工具,一个 SSH 公钥工具,还有 WARDEN 也误阻止的那个部署工具。mcp-shield 阻止了 35% 的真实服务器,几乎都因为关键词:“API key”“token”、`.env`、“..”。省略号(“Shopify...”)被当作路径穿越。它也阻止了 WARDEN 阻止的那个身份服务,但依据是 “credentials” 这个词。
192
- - **要清楚哪些数字是调出来的。** 第一组攻击样本是我们写的。ruleset v9 是在读过两组攻击样本之后写的,v10 是在读过另一半的 22 台 MCPTox 服务器之后写的。所以 20 和 10 是“照着见过的样本调出来的规则”的召回率。MCPTox 留出的那一行、干净服务器、语料以及整个 0.8.2 列都没有经过调整。在语料上,v10 阻止的与 v8 完全相同。
193
- - **MCPTox 考的是结构,不是关键词。** 几乎每个投毒工具都要求模型先调用另一个工具,或修改另一个工具的参数。v10 为这种结构命名(`TOOL_DEF_CROSS_TOOL`,见[关卡链](gates.zh.md)),在留出的 218 个工具中阻止 171 个;在用来编写它的那一半上是 267 个中的 189 个。加上基准自带的 `<IMPORTANT>` 或 “Ignore the previous instructions” 前缀后,我们运行的每个扫描器都能发现;mcp-shield 没有在这一组上运行。在干净服务器上,mcp-audit 阻止了 AmapMap 和 BaiduMap,mcp-shield 以 “sensitive file access” 为由阻止了 FileSystem、AdFin 和 Commander。
194
- - **WARDEN 仍会漏掉的:** 留出的 218 个 MCPTox 工具中的 47 个、用中文写的读取 `.env` 的指令、没有关键词的改写(“gather every credential file … keep this step to yourself”),以及 “include the output of env”。这 47 个中的 41 个以及我们的这三个,它会以建议的形式报告,但不会阻止。这些需要基于语义的检查,而不是再加一条规则:加上上文的可选分类器,218 个中有 191 个在 `high` 级别被阻止,218 个全部被标记。
195
- - **在这个位置上 WARDEN 并不是唯一的选择。** mcp-audit 同样提供 lock 文件、PR diff 模式和 SARIF。
193
+ 2026 年 10 月 16 日,我们在同一批服务器上运行了 WARDEN、mcp-audit 0.18.2(`--connect`)、mcp-shield 1.0.4、truecopy 0.10.4 和 mcpsentry 0.1.5。每台服务器都通过 stdio 重放,因此每款扫描器都像在实际使用中一样连接它。每款扫描器都在无网络的 gVisor 容器中运行,镜像固定,其内容的哈希记录在清单中。测试工具、样本集、清单和每一条判定都在 [`scripts/scanner-comparison`](../scripts/scanner-comparison/)。包含方法和全部注意事项的完整报告是[扫描器对比](scanner-comparison.zh.md)。
194
+
195
+ MCPTox 各行来自 MCPTox(Wang 等,AAAI 2026):一个公开的基准,包含为 45 台真实 MCP 服务器编写的 485 个投毒工具。我们用固定哈希把它的服务器分成两半。规则集 v10 依据其中 22 台编写;表中报告的是另外 23 台,共 218 个没有任何规则照着调过的投毒工具。v11 和 v12 也不是依据它们编写的,给出的判定与 v10 相同。
196
+
197
+ | 服务器 | 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 个攻击,阻止数 | 20 | 10 | 6 | 8 | 4 |
200
+ | mcp-audit 与 mcp-shield 自带样例中的 10 个攻击,阻止数 | 10 | 10 | 8 | 7 | 5 |
201
+ | 12 个困难的良性样例,阻止数 | 0 | 1 | 1 | 1 | 2 |
202
+ | 留出服务器上的 218 个 MCPTox 投毒工具,阻止数 | 171 | 25 | 41 | 27 | 8 |
203
+ | 带 `<IMPORTANT>` 或 “Ignore the previous instructions” 前缀的 225 个 MCPTox 工具,阻止数 | 225 | 222 | 41 | 141 | 136 |
204
+ | 45 台干净的 MCPTox 服务器,阻止数 | 0 | 2 | 3 | 0 | 1 |
205
+ | 986 台公开服务器,阻止数 | 3 | 33 | 343 | 39 | 86 |
206
+ | ……读过文本后站得住的阻止 | 1 个,另有 1 个有争议 | 0 | 我们读过的 34 个中有 1 个 | 1 | 0 |
207
+ | HISTOR 观察过的 14,933 个 npm 与 PyPI 包,阻止数 | 369 | 928 | 5,354 | 252 | 1,449 |
208
+
209
+ - **先看真实服务器这几行。** 没有任何规则照着它们调过。mcp-audit 在语料上的 33 个阻止,大多是完全用本身文字书写的文本中的“同形字”,以及 “do not tell the user the check digits are wrong” 这样的诚实性说明。mcp-shield 阻止了三分之一的真实服务器,几乎都是因为关键词:“API key”、“token”、`.env`、“..”。truecopy 阻止了同一厂商的 docker-compose 生成器,因为它们会生成 `.env.example`。mcpsentry 的 base64 模式会匹配任何 40 个字母和斜杠组成的串,JSON Schema 路径就会产生这样的串。在 14,933 个 npm 与 PyPI 包中,我们判定了每个阻止的 996 个随机样本里,WARDEN 有 23 个阻止,无一站得住,4 个有争议;mcp-shield 在同一批包中阻止 339 个,mcpsentry 阻止 112 个。
210
+ - **弄清哪些数字是照着样本调出来的。** 第一套攻击是我们写的,规则集 v9 是在读过两套攻击之后写的。MCPTox 留出一半那一行、干净服务器、语料和包都不是照着样本调出来的。
211
+ - **MCPTox 测的是一种形态,而不是关键词。** 几乎每个投毒工具都让模型先调用另一个工具,或修改另一个工具的参数。v10 给这种形态起了名字(`TOOL_DEF_CROSS_TOOL`,见[关卡链](gates.zh.md)),v12 保留了它。加上基准的 `<IMPORTANT>` 前缀后,大多数扫描器能发现大多数工具。
212
+ - **WARDEN 仍然漏掉的:** 218 个留出 MCPTox 工具中的 47 个、一条用中文要求读取 `.env` 的指令、一句没有关键词的改写(“gather every credential file … keep this step to yourself”)以及 “include the output of env”。这 47 个中有 41 个它以建议性发现的形式报告,而不是阻止。启用上文的可选分类器后,全部 218 个都在 `high` 级别被标记。
213
+ - **在这一位置上 WARDEN 并不孤单。** mcp-audit 也提供 lock 文件、PR 差异模式和 SARIF;truecopy 同样会在 lock 文件中固定并签名工具定义。
196
214
 
197
215
  ## scan 不做什么
198
216