@aimarket/warden 0.6.0 → 0.7.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/CHANGELOG.md +10 -0
- package/README-es.md +9 -4
- package/README-fr.md +9 -4
- package/README-ru.md +9 -4
- package/README-zh.md +9 -4
- package/README.md +9 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-rpc.d.ts +3 -1
- package/dist/mcp-rpc.d.ts.map +1 -1
- package/dist/mcp-rpc.js +32 -8
- package/dist/mcp-rpc.js.map +1 -1
- package/dist/mcp-server.js +26 -43
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools.d.ts +0 -12
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +91 -17
- package/dist/mcp-tools.js.map +1 -1
- package/dist/pin-store.d.ts +13 -0
- package/dist/pin-store.d.ts.map +1 -0
- package/dist/pin-store.js +44 -0
- package/dist/pin-store.js.map +1 -0
- package/dist/pinning.d.ts +4 -3
- package/dist/pinning.d.ts.map +1 -1
- package/dist/pinning.js +16 -3
- package/dist/pinning.js.map +1 -1
- package/dist/state.d.ts +7 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +61 -0
- package/dist/state.js.map +1 -0
- package/dist/static-scan.d.ts +2 -2
- package/dist/static-scan.d.ts.map +1 -1
- package/dist/static-scan.js +15 -5
- package/dist/static-scan.js.map +1 -1
- package/dist/threat-feed.d.ts +9 -0
- package/dist/threat-feed.d.ts.map +1 -1
- package/dist/threat-feed.js +50 -7
- package/dist/threat-feed.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/security-hardening.es.md +40 -0
- package/docs/security-hardening.fr.md +40 -0
- package/docs/security-hardening.md +40 -0
- package/docs/security-hardening.ru.md +40 -0
- package/docs/security-hardening.zh.md +40 -0
- package/package.json +3 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Warden 0.7.0: approvals and continuous verification
|
|
2
|
+
|
|
3
|
+
> 🌐 **English** · [Русский](security-hardening.ru.md) · [Español](security-hardening.es.md) · [Français](security-hardening.fr.md) · [中文](security-hardening.zh.md)
|
|
4
|
+
|
|
5
|
+
Warden 0.7.0 and ARGUS 0.3.2 close six gaps. This is a definition and launch-configuration firewall, not an operating-system sandbox or a guarantee about server behaviour.
|
|
6
|
+
|
|
7
|
+
1. **Before connection.** Call `warden.vetLaunch(server)` before spawning a stdio process or opening a remote transport. It checks origin, known command/endpoint threats and the pinned launch identity. Once connected, obtain the complete `tools/list` and call `vet(server, tools)` before exposing tools. A successful launch check alone does not approve tools.
|
|
8
|
+
2. **Signed feed rollback.** The last accepted timestamp, content digest and records are stored per publisher key under `feeds/`. An older timestamp, or different content with the same timestamp, is rejected even after restart. A newer signed snapshot can intentionally remove a rule. Failed updates retain the last-good records; `feed.status.stale` reports freshness separately, so retained rules are not presented as current intelligence. The ten-second deadline covers headers and the complete body. The byte and record caps still apply.
|
|
9
|
+
3. **Stdio.** Invalid JSON-RPC envelopes return `-32600`, invalid parameters return `-32602`, and syntax errors return `-32700`. UTF-8 is decoded only after a complete frame arrives. Frames are limited to 1 MiB; legacy Content-Length headers to 8 KiB. Oversized or invalid framing terminates the connection deliberately; invalid request objects do not. The separate tool-argument limit remains 256,000 characters.
|
|
10
|
+
4. **Durable approvals.** `vet_mcp_server` reads persisted pins. `status_mcp_server({server, tools})` returns `previous`, `previousRevision`, `currentTools`, `currentToolsHash`, `currentIdentityHash` and `changed` for review. Approval requires the exact reviewed tool and identity hashes and `previous_pin_revision` (null for first approval). Revocation also requires the previous revision. Concurrent changes invalidate a stale review. Definitions are retained for comparison; never put live credentials in them.
|
|
11
|
+
5. **Complete definitions.** Hash format v2 pins all advertised fields, including `title`, `outputSchema`, `annotations` and extension metadata. Undefined top-level fields are omitted. Plain name/description/inputSchema payloads keep their existing digest. Legacy pins that did not cover extended fields require explicit reapproval (`PIN_FORMAT_UPGRADE_REQUIRED`); new pins record `toolsHashVersion: 2`. Ruleset v6 scans these additional surfaces. JSON delimiters around a schema description are not treated as evidence that an instruction is merely a quotation. Annotations remain untrusted hints and grant no permissions.
|
|
12
|
+
6. **During the session.** ARGUS quarantines tools immediately on `notifications/tools/list_changed` and rechecks all pages. It also rechecks before every tool call, including when a server sends no notification. Old wrappers are tied to the definitions the user/model saw and cannot execute a changed definition after reapproval. Listing failures, duplicate names, repeated cursors, over 32 pages, over 256 tools or over 1 MiB of listed definitions fail closed. Drift is never automatically reapproved. Initial clean connections retain ARGUS's existing automatic first-pin policy; this is not a human review step. Pin-write failure now closes the connection. A change during execution withholds the result, but cannot undo an already performed side effect; do not retry automatically.
|
|
13
|
+
|
|
14
|
+
## State and operator permissions
|
|
15
|
+
|
|
16
|
+
The state directory is `WARDEN_STATE_DIR`, otherwise `$XDG_STATE_HOME/warden`, otherwise `~/.local/state/warden`. A library caller can supply `ThreatFeed({stateDir})` or `FilePinStore(directory)`. ARGUS stores feed state below its configured memory directory (`warden/`). Pin files use hashed server IDs, atomic replacement and owner-only permissions; writes use per-file locks. If a process dies while holding a lock, later mutation fails closed. Stop all writers, inspect the state and remove only the abandoned `.lock` file; do not delete snapshots to silence an error. Keep the directory on a persistent local volume. Deleting it discards approvals and rollback history.
|
|
17
|
+
|
|
18
|
+
By default MCP approval mutations are disabled. The operator may set `WARDEN_ALLOW_PIN_CHANGES=1` **before starting** `warden-mcp`. This delegates approval/revocation capability to that MCP client; a request argument cannot enable it. Human review must be enforced by the host or by using a separate operator session. Scanning never approves silently, and reapproval must still pass the other security gates.
|
|
19
|
+
|
|
20
|
+
## Upgrade and limits
|
|
21
|
+
|
|
22
|
+
Publish/install `@aimarket/warden@0.7.0` first, then `@alexar76/argus3@0.3.2`, which pins that dependency. Restart MCP clients. Review legacy-pin migration findings rather than deleting pins. Other hosts must wire `vetLaunch` and runtime revalidation themselves. Neither hash comparisons nor notifications detect a backend changing its behaviour while advertising identical definitions. Tool results remain untrusted; these changes do not implement result-content screening or process isolation. Added local regression tests cover rollback/restart, body timeout, split UTF-8, invalid messages, approval persistence, metadata drift and ARGUS call blocking. No paid calls or production deployment are required to run them.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const state = (await client.callTool({
|
|
26
|
+
name: "status_mcp_server", arguments: { server, tools },
|
|
27
|
+
})).structuredContent;
|
|
28
|
+
// Review state.previous against state.currentTools and the launch identity first.
|
|
29
|
+
await client.callTool({ name: "approve_mcp_server", arguments: {
|
|
30
|
+
server, tools,
|
|
31
|
+
reviewed_tools_hash: state.currentToolsHash,
|
|
32
|
+
reviewed_identity_hash: state.currentIdentityHash,
|
|
33
|
+
previous_pin_revision: state.previousRevision,
|
|
34
|
+
} });
|
|
35
|
+
const verdict = (await client.callTool({
|
|
36
|
+
name: "vet_mcp_server", arguments: { server, tools },
|
|
37
|
+
})).structuredContent;
|
|
38
|
+
if (!verdict.allow) throw new Error("WARDEN blocked the server");
|
|
39
|
+
// Revoke using a freshly reviewed status, not the pre-approval revision.
|
|
40
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Warden 0.7.0: одобрения и повторная проверка
|
|
2
|
+
|
|
3
|
+
> 🌐 [English](security-hardening.md) · **Русский** · [Español](security-hardening.es.md) · [Français](security-hardening.fr.md) · [中文](security-hardening.zh.md)
|
|
4
|
+
|
|
5
|
+
Warden 0.7.0 и ARGUS 0.3.2 закрывают шесть разрывов. Warden проверяет определения инструментов и настройки запуска; он не является песочницей ОС и не гарантирует поведение сервера.
|
|
6
|
+
|
|
7
|
+
1. **До подключения.** Вызывать `warden.vetLaunch(server)` до запуска stdio-процесса или открытия удалённого соединения. Проверяются происхождение, известные опасные команды/адреса и ранее одобренная идентичность запуска. После подключения получить полный `tools/list` и вызвать `vet(server, tools)` до передачи инструментов модели. Успешная предпроверка запуска сама по себе не одобряет инструменты.
|
|
8
|
+
2. **Откат подписанной базы угроз.** Последние принятые timestamp, digest и записи сохраняются отдельно для каждого ключа издателя в `feeds/`. Более старый снимок и другой контент с тем же timestamp отклоняются, включая после перезапуска. Более новый подписанный снимок может намеренно удалить правило. При ошибке обновления остаются последние принятые правила; `feed.status.stale` отдельно показывает их свежесть. Таймаут десять секунд охватывает заголовки и всё тело ответа. Ограничения размера и числа записей сохраняются.
|
|
9
|
+
3. **Stdio.** Некорректная структура JSON-RPC возвращает `-32600`, параметры — `-32602`, синтаксис JSON — `-32700`. UTF-8 декодируется после получения целого сообщения. Предел сообщения — 1 MiB, заголовка старого Content-Length — 8 KiB. Превышение предела или повреждённый фрейм намеренно закрывают соединение; некорректный объект запроса процесс не завершает. Отдельный предел аргументов инструмента — 256 000 символов.
|
|
10
|
+
4. **Постоянные одобрения.** `vet_mcp_server` читает сохранённые отпечатки. `status_mcp_server({server, tools})` возвращает `previous`, `previousRevision`, `currentTools`, `currentToolsHash`, `currentIdentityHash`, `changed` для сравнения. Одобрение требует точных рассмотренных хешей инструментов и запуска, а также `previous_pin_revision` (null при первом одобрении). Отзыв тоже требует предыдущую ревизию. Конкурентное изменение делает старое решение неприменимым. Определения сохраняются для сравнения: не помещайте в них действующие секреты.
|
|
11
|
+
5. **Полные определения.** Формат отпечатка v2 включает все объявленные поля, в том числе `title`, `outputSchema`, `annotations` и расширения. Верхнеуровневые поля со значением undefined пропускаются. Для обычных name/description/inputSchema прежний digest сохраняется. Старые одобрения, не покрывавшие расширенные поля, требуют явного переодобрения (`PIN_FORMAT_UPGRADE_REQUIRED`); новые содержат `toolsHashVersion: 2`. Набор правил v6 проверяет дополнительные поверхности. JSON-кавычки вокруг описания схемы больше не считаются доказательством безобидного цитирования инструкции. Аннотации остаются недоверенными подсказками, не разрешениями.
|
|
12
|
+
6. **Во время сессии.** При `notifications/tools/list_changed` ARGUS немедленно приостанавливает инструменты и перепроверяет все страницы списка. Повторная проверка есть и перед каждым вызовом — даже без уведомлений сервера. Старые ссылки привязаны к определениям, которые видел пользователь/модель, и не выполняют изменённый инструмент после переодобрения. Ошибки получения списка, одинаковые имена, повтор курсора, более 32 страниц, 256 инструментов или 1 MiB определений блокируют использование. Изменения не переодобряются автоматически. Для первого чистого подключения сохраняется прежняя политика ARGUS: автоматическая запись первого отпечатка; это не ручная проверка человеком. Ошибка записи теперь закрывает соединение. Изменение во время исполнения скрывает результат, но не отменяет уже совершённое действие — автоматически повторять вызов нельзя.
|
|
13
|
+
|
|
14
|
+
## Хранение и права оператора
|
|
15
|
+
|
|
16
|
+
Каталог состояния: `WARDEN_STATE_DIR`, иначе `$XDG_STATE_HOME/warden`, иначе `~/.local/state/warden`. В библиотеке можно задать `ThreatFeed({stateDir})` или `FilePinStore(directory)`. ARGUS хранит базу угроз в `warden/` внутри своего каталога памяти. Имена файлов одобрений получаются из хеша server ID; запись атомарная, права — только владельцу, изменения защищены отдельными файловыми блокировками. Если процесс погиб с блокировкой, дальнейшее изменение отклоняется. Остановить всех писателей, проверить состояние и удалить только оставшийся `.lock`; не удалять снимки ради устранения ошибки. Использовать постоянный локальный том. Удаление каталога стирает одобрения и историю защиты от отката.
|
|
17
|
+
|
|
18
|
+
По умолчанию MCP не разрешает изменять одобрения. Оператор может установить `WARDEN_ALLOW_PIN_CHANGES=1` **до запуска** `warden-mcp`. Это делегирует MCP-клиенту право одобрения и отзыва; аргумент запроса включить его не может. Если нужна ручная проверка, её обеспечивает хост или отдельная операторская сессия. Сканирование само не одобряет сервер, а переодобрение обязано пройти остальные проверки безопасности.
|
|
19
|
+
|
|
20
|
+
## Обновление и границы
|
|
21
|
+
|
|
22
|
+
Сначала опубликовать/установить `@aimarket/warden@0.7.0`, затем `@alexar76/argus3@0.3.2`, который закрепляет эту зависимость. Перезапустить MCP-клиенты. При миграции изучить предупреждение и определения, а не удалять одобрения. В других хостах `vetLaunch` и повторную проверку необходимо подключить самостоятельно. Неизменные объявления не позволяют обнаружить изменение поведения внутреннего кода сервера. Результаты инструментов остаются недоверенными: фильтр содержимого результатов и изоляция процессов этим релизом не добавлены. Локальные регрессионные тесты проверяют откат/перезапуск, таймаут тела, разрыв UTF-8, некорректные сообщения, сохранение одобрений, изменение метаданных и блокировку вызовов ARGUS. Платные вызовы и выкладка на прод для этих тестов не требуются.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const state = (await client.callTool({
|
|
26
|
+
name: "status_mcp_server", arguments: { server, tools },
|
|
27
|
+
})).structuredContent;
|
|
28
|
+
// Review state.previous against state.currentTools and the launch identity first.
|
|
29
|
+
await client.callTool({ name: "approve_mcp_server", arguments: {
|
|
30
|
+
server, tools,
|
|
31
|
+
reviewed_tools_hash: state.currentToolsHash,
|
|
32
|
+
reviewed_identity_hash: state.currentIdentityHash,
|
|
33
|
+
previous_pin_revision: state.previousRevision,
|
|
34
|
+
} });
|
|
35
|
+
const verdict = (await client.callTool({
|
|
36
|
+
name: "vet_mcp_server", arguments: { server, tools },
|
|
37
|
+
})).structuredContent;
|
|
38
|
+
if (!verdict.allow) throw new Error("WARDEN blocked the server");
|
|
39
|
+
// Revoke using a freshly reviewed status, not the pre-approval revision.
|
|
40
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Warden 0.7.0:持久审批与持续验证
|
|
2
|
+
|
|
3
|
+
> 🌐 [English](security-hardening.md) · [Русский](security-hardening.ru.md) · [Español](security-hardening.es.md) · [Français](security-hardening.fr.md) · **中文**
|
|
4
|
+
|
|
5
|
+
Warden 0.7.0 和 ARGUS 0.3.2 修复六个缺口。它检查工具定义和启动配置,不是操作系统沙箱,也不保证服务器实际行为安全。
|
|
6
|
+
|
|
7
|
+
1. **连接之前。** 在启动 stdio 进程或建立远程连接前调用 `warden.vetLaunch(server)`,检查来源、已知危险命令/地址及已批准的启动身份。连接后获取完整分页 `tools/list`,再调用 `vet(server, tools)`,通过后才向模型暴露工具。启动检查通过不等于工具已获批准。
|
|
8
|
+
2. **签名威胁库防回滚。** 按发布者公钥在 `feeds/` 保存最后接受的 timestamp、digest 和记录。拒绝较旧时间戳,以及相同时间戳下不同的内容;重启后仍有效。更新的合法签名快照可以主动删除规则。更新失败时保留最后有效的规则;`feed.status.stale` 单独说明新鲜度,保留规则不代表它们是最新情报。十秒超时覆盖响应头和完整响应体,字节数及记录数限制继续有效。
|
|
9
|
+
3. **Stdio。** 错误 JSON-RPC 结构返回 `-32600`,错误参数返回 `-32602`,JSON 语法错误返回 `-32700`。收到完整帧后才解码 UTF-8。每帧最多 1 MiB,旧式 Content-Length 头最多 8 KiB。超限或损坏的帧会主动关闭连接;错误的请求对象不会结束进程。工具参数仍有独立的 256 000 字符限制。
|
|
10
|
+
4. **持久审批。** `vet_mcp_server` 读取已保存的指纹。`status_mcp_server({server, tools})` 返回 `previous`、`previousRevision`、`currentTools`、`currentToolsHash`、`currentIdentityHash`、`changed` 供比较。批准必须提供已审阅的准确工具哈希、启动身份哈希及 `previous_pin_revision`(首次为 null)。撤销也需要上一版本标识;并发更新会使旧审阅失效。工具定义会保存用于比较,请勿写入真实凭据。
|
|
11
|
+
5. **完整定义。** 指纹格式 v2 包含所有公布字段,包括 `title`、`outputSchema`、`annotations` 和扩展元数据;忽略顶层 undefined 字段。只有 name/description/inputSchema 的定义保留原 digest。未覆盖扩展字段的旧审批需要明确重新批准(`PIN_FORMAT_UPGRADE_REQUIRED`);新记录包含 `toolsHashVersion: 2`。规则集 v6 扫描新增字段。JSON 序列化引号不再被误认为“指令只是无害引用”。注解始终是不可信提示,不授予权限。
|
|
12
|
+
6. **会话期间。** 收到 `notifications/tools/list_changed` 后,ARGUS 立即暂停工具并重新检查所有页面。每次工具调用前也重新检查,覆盖不发通知的服务器。旧工具引用绑定用户/模型曾看到的定义,重新批准后也不能调用已经变化的定义。列表获取失败、重名、重复游标、超过 32 页、256 个工具或 1 MiB 定义时阻止使用。变化不会自动重新批准。首次正常连接保留 ARGUS 原有的自动首次记录策略,这不表示人工审阅。记录失败现在会关闭连接。执行期间发生变化会隐藏结果,但不能撤销已发生的副作用,请勿自动重试。
|
|
13
|
+
|
|
14
|
+
## 状态存储与操作员权限
|
|
15
|
+
|
|
16
|
+
状态目录依次为 `WARDEN_STATE_DIR`、`$XDG_STATE_HOME/warden`、`~/.local/state/warden`。库调用可指定 `ThreatFeed({stateDir})` 或 `FilePinStore(directory)`。ARGUS 在配置的内存目录下使用 `warden/` 保存威胁库。审批文件名由服务器 ID 的哈希生成,采用原子替换、仅所有者权限和逐文件锁。进程持锁崩溃后,后续修改会安全失败:停止所有写入进程,检查状态,只删除遗留 `.lock`;不要删除快照来掩盖错误。使用持久本地卷。删除目录会丢失审批及防回滚历史。
|
|
17
|
+
|
|
18
|
+
MCP 默认禁止修改审批。操作员可在启动 `warden-mcp` 前设置 `WARDEN_ALLOW_PIN_CHANGES=1`。这会向该 MCP 客户端授予批准/撤销能力,请求参数不能开启它。人工审阅须由宿主或独立操作员会话落实。扫描不自动批准,重新批准仍须通过其他安全检查。
|
|
19
|
+
|
|
20
|
+
## 升级与边界
|
|
21
|
+
|
|
22
|
+
先发布/安装 `@aimarket/warden@0.7.0`,再发布/安装依赖该版本的 `@alexar76/argus3@0.3.2`,然后重启 MCP 客户端。审阅旧审批迁移提示,不要直接删除审批。其他宿主须自行接入 `vetLaunch` 和运行期间复查。定义完全相同时,哈希无法检测后端行为改变。工具结果仍是不可信数据;本次不提供结果内容过滤或进程隔离。新增本地回归测试覆盖回滚、重启、响应体超时、UTF-8 分片、非法请求、审批持久化、元数据漂移和 ARGUS 调用阻止,不需要付费调用或生产部署。
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const state = (await client.callTool({
|
|
26
|
+
name: "status_mcp_server", arguments: { server, tools },
|
|
27
|
+
})).structuredContent;
|
|
28
|
+
// Review state.previous against state.currentTools and the launch identity first.
|
|
29
|
+
await client.callTool({ name: "approve_mcp_server", arguments: {
|
|
30
|
+
server, tools,
|
|
31
|
+
reviewed_tools_hash: state.currentToolsHash,
|
|
32
|
+
reviewed_identity_hash: state.currentIdentityHash,
|
|
33
|
+
previous_pin_revision: state.previousRevision,
|
|
34
|
+
} });
|
|
35
|
+
const verdict = (await client.callTool({
|
|
36
|
+
name: "vet_mcp_server", arguments: { server, tools },
|
|
37
|
+
})).structuredContent;
|
|
38
|
+
if (!verdict.allow) throw new Error("WARDEN blocked the server");
|
|
39
|
+
// Revoke using a freshly reviewed status, not the pre-approval revision.
|
|
40
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aimarket/warden",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "WARDEN — MCP security firewall. Library + stdio MCP server: vets tool definitions (static-scan → threat-feed → origin → pinning) before they reach the model. Zero npm runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"README-fr.md",
|
|
40
40
|
"README-zh.md",
|
|
41
41
|
"CHANGELOG.md",
|
|
42
|
-
"LICENSE"
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"docs/security-hardening*.md"
|
|
43
44
|
],
|
|
44
45
|
"engines": {
|
|
45
46
|
"node": ">=20"
|