@aimarket/warden 0.20.0 → 0.21.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 (65) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README-es.md +26 -11
  3. package/README-fr.md +26 -11
  4. package/README-ru.md +26 -11
  5. package/README-zh.md +26 -11
  6. package/README.md +26 -11
  7. package/dist/atomic-screen.d.ts +61 -0
  8. package/dist/atomic-screen.d.ts.map +1 -0
  9. package/dist/atomic-screen.js +165 -0
  10. package/dist/atomic-screen.js.map +1 -0
  11. package/dist/flow-guard.d.ts +181 -2
  12. package/dist/flow-guard.d.ts.map +1 -1
  13. package/dist/flow-guard.js +1194 -72
  14. package/dist/flow-guard.js.map +1 -1
  15. package/dist/mcp-server.js +5 -0
  16. package/dist/mcp-server.js.map +1 -1
  17. package/dist/mcp-tools.d.ts.map +1 -1
  18. package/dist/mcp-tools.js +46 -9
  19. package/dist/mcp-tools.js.map +1 -1
  20. package/dist/review-diff.d.ts +36 -0
  21. package/dist/review-diff.d.ts.map +1 -1
  22. package/dist/review-diff.js +179 -7
  23. package/dist/review-diff.js.map +1 -1
  24. package/dist/task-adapter.d.ts +73 -0
  25. package/dist/task-adapter.d.ts.map +1 -0
  26. package/dist/task-adapter.js +379 -0
  27. package/dist/task-adapter.js.map +1 -0
  28. package/dist/task-cli.d.ts +3 -0
  29. package/dist/task-cli.d.ts.map +1 -0
  30. package/dist/task-cli.js +162 -0
  31. package/dist/task-cli.js.map +1 -0
  32. package/dist/types.d.ts +9 -0
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/wrap-cli.d.ts +5 -0
  35. package/dist/wrap-cli.d.ts.map +1 -1
  36. package/dist/wrap-cli.js +27 -1
  37. package/dist/wrap-cli.js.map +1 -1
  38. package/dist/wrap-screen.d.ts +3 -0
  39. package/dist/wrap-screen.d.ts.map +1 -0
  40. package/dist/wrap-screen.js +20 -0
  41. package/dist/wrap-screen.js.map +1 -0
  42. package/dist/wrap-state.d.ts +5 -0
  43. package/dist/wrap-state.d.ts.map +1 -1
  44. package/dist/wrap-state.js +3 -1
  45. package/dist/wrap-state.js.map +1 -1
  46. package/dist/wrap.d.ts.map +1 -1
  47. package/dist/wrap.js +161 -5
  48. package/dist/wrap.js.map +1 -1
  49. package/docs/flow-guard.es.md +274 -9
  50. package/docs/flow-guard.fr.md +274 -9
  51. package/docs/flow-guard.md +275 -10
  52. package/docs/flow-guard.ru.md +275 -10
  53. package/docs/flow-guard.zh.md +273 -5
  54. package/docs/security-hardening.es.md +1 -1
  55. package/docs/security-hardening.fr.md +1 -1
  56. package/docs/security-hardening.md +1 -1
  57. package/docs/security-hardening.ru.md +1 -1
  58. package/docs/security-hardening.zh.md +1 -1
  59. package/examples/atomic-screen-server.mjs +42 -0
  60. package/native/macos/Package.swift +9 -0
  61. package/native/macos/Sources/WardenDesktop/NativeSurface.swift +246 -0
  62. package/native/macos/Sources/WardenDesktop/StandardIO.swift +139 -0
  63. package/native/macos/Sources/WardenDesktopHost/Main.swift +211 -0
  64. package/package.json +17 -5
  65. package/scripts/build-macos.mjs +22 -0
@@ -2,6 +2,273 @@
2
2
 
3
3
  > 🌐 [English](flow-guard.md) · **Русский** · [Español](flow-guard.es.md) · [Français](flow-guard.fr.md) · [中文](flow-guard.zh.md)
4
4
 
5
+ Повторный аудит, 2026-10-23: бинарные данные `image`/`audio` в результатах инструментов больше не расходуют лимит текста: большое изображение перед текстом не скрывает подписи элементов, заголовки окон с именами файлов учётных данных и JSON в текстовых блоках. Экраны из результатов кликов и нажатий клавиш, включая действия `computer`, тоже обновляют карту. Простое подтверждение выполнения сохраняет предыдущую карту; результат действия только с изображением очищает её. Для исходящих аргументов исключения нет: секрет, замаскированный под бинарные данные, по-прежнему проверяется. Регрессионные тесты воспроизводят оба обхода через hooks и настоящий stdio-прокси. В локальных исходниках теперь также проверяются непрозрачные действия GUI, как описано ниже.
6
+
7
+ Эти исправления управления экраном входят в npm `0.21.0`. В npm `0.20.0` их не было.
8
+
9
+ ## Граница учётных данных и закодированные фрагменты (локальный код, 2026-10-23)
10
+
11
+ После зарегистрированных чтения ключа и внешнего текста **каждый поддерживаемый исходящий/MCP-вызов требует `ask` до исполнения** (режим `deny` отказывает), независимо от длины части, кодировки, названного адресата и метки MCP «только чтение». Обычные записи в проект тоже проверяются; прежнее исключение для файлов учётных данных сохранено. Флаг `credentialRead` не сбрасывается при вытеснении старых источников или новом ходе пользователя. Так автоматическая передача частей по одному–четыре символа и неизвестных закодированных данных закрывается общей границей, а не обещанием декодировать что угодно.
12
+
13
+ Известное совпадение с секретом по-прежнему запрещается, неоднозначный короткий фрагмент получает `secret_fragment`. Прочие запросы границы имеют причину `credential_egress`, а не ложное утверждение, что безвредный текст — секрет. Строгий GUI остаётся стандартным; его исключения, включая копирование, эту границу не отменяют. `audit` только записывает, `off` отключает защиту; клиент должен соблюдать решения.
14
+
15
+ **Как уменьшить лишние подтверждения:** оператор может добавить точные, независимо проверенные публичные запросы в защищённый пользовательский `flow-policy.json`. Правило связывает полное имя инструмента и все аргументы, включая адресата, через `publicRequestDigest(tool, args)` из `dist/flow-guard.js`. Ключи объектов сортируются, порядок массива значим. Каждое правило разрешает максимум один вызов за сессию, атомарно между прокси, и расходуется даже при ошибке исполнения. Повторы, изменения, дополнительные метаданные RPC и некорректные аргументы не покрываются. Правила не освобождают найденные секреты/приватный текст/персональные данные/короткие совпадения, неполную проверку, переполненное хранилище, управление GUI, shell-код, разрушительные действия и защищённые настройки. Правило разрешает ровно заданные данные, а не доказывает их публичность. Перед одобрением кодированных данных самостоятельно проверьте расшифрованное содержимое. Правила автоматически не устанавливаются.
16
+
17
+ Пример разрешает только `mcp__mail__send_email` с `{"to":"bob@corp.com","subject":"status","body":"The public release is ready."}`:
18
+
19
+ ```json
20
+ {"credentialEgress":{"allow":[{"tool":"mcp__mail__send_email","requestSha256":"62e02f4cb9c21a472999fac9316b66fc8fefe3fcafd2b2860c32c5409dae4a65"}]}}
21
+ ```
22
+
23
+ При исполнении с защитой потока пересылается проверенный JSON-объект без проигнорированных дубликатов полей; скрытые значения не проходят вместе с точным разрешением.
24
+
25
+ Отпечаток создаётся локально через `publicRequestDigest` после проверки всего запроса. Лимиты: 32 правила/использованных разрешения, 1 024 JSON-узла, глубина 32, 16 384 единицы UTF-16 в сериализованном запросе и 65 536 единиц работы сериализации. Некорректный раздел не даёт разрешений. Журнал: `credential_public_request` / `policy_allowed`, исход подтверждения unknown; это не утверждение о нажатии человеком формы.
26
+
27
+ Метаданные фрагментов сохраняют версию `v2`. Подтверждения безвредных запросов: **12/12 → 0/12** с точными проверенными правилами; цена стандартного режима остаётся явной.
28
+
29
+ **Декодирование и ошибки:** ограниченная очередь совмещает URL, канонические base64/base64url, UTF-8 hex, скалярные Unicode/hex escape-последовательности, числовые HTML-сущности и явные английские списки символов. Максимум: четыре уровня преобразования, 64 кандидата, суммарно 524 288 единиц UTF-16. Исчерпание бюджета даёт `payload_incomplete` и проверку человеком, а не «чистый» результат или разрешение правила. Некорректные литералы не исполняются; распаковки и смыслового угадывания нет. Повреждённое состояние/отпечатки не разрешают вызов. Старый индекс v1 требует проверки; для полного восстановления нужна новая сессия и повторное чтение приватных источников. Хеши/смещения/размеры и ограниченные исходящие хвосты остаются чувствительными данными, шифрования нет.
30
+
31
+ **Измеренный компромисс:** в проверке рабочих сценариев — 12 безвредных запросов и 16 атак. Строгий стандартный режим запрашивает все 12 безвредных вызовов; точные проверенные правила пропускают все 12 по одному разу. В обоих вариантах автоматически проходит **0/16 атак**, жёстких ложных запретов — **0**. Отдельный замер только отпечатков: 480 вымышленных ключей, 758 файлов, 0 жёстких запретов и 2 файла с коротким совпадением, требующим проверки. Это разные измерения, они не доказывают частоту ложных срабатываний на проде. Прежний набор из 23 сценариев остаётся на **0/23 прошедших целиком**, включая `secret-chunks-6-filler` и `secret-spelled-out`; два сценария только с ответом получают пояснение/перепроверку. Настоящие stdio-тесты подтверждают ноль вызовов сервера для неподтверждённых коротких/неизвестно закодированных данных, одно разрешение между параллельными прокси и отсутствие обхода через метаданные или повторы.
32
+
33
+ ```bash
34
+ npm run build
35
+ npm test
36
+ node scripts/redteam/credential-egress.mjs /tmp/warden-egress.json
37
+ node scripts/redteam/flow-redteam.mjs /tmp/warden-redteam.json
38
+ node scripts/redteam/fragment-collisions.mjs /tmp/warden-fragments.json docs src test ../docs ../core
39
+ ```
40
+
41
+ **Пределы:** это контроль зарегистрированной границы инструментов, а не всеобщий анализ информационных потоков. Непрочитанные источники, неизвестные/переименованные интеграции, ответы без вызова инструмента, временные/скрытые каналы, скрытое поведение сервера, явно одобренная передача и клиенты, обходящие решения, гарантией не покрыты. Без проверенных правил подтверждений для безвредных действий намеренно больше. Прод и npm не обновлены; oracle replay AgentDojo перезапущен ниже; прежние измерения с моделью и 115 млн символов/HISTOR не повторялись.
42
+
43
+ ## Непрозрачные действия GUI (локальные исходники, 2026-10-23)
44
+
45
+ В строгом режиме GUI по умолчанию после недоверенных данных распознанные вызовы указателя и клавиатуры MCP запрашивают подтверждение до исполнения (`deny` отказывает). Автоматический пропуск кликов по координатам, экранов из одних пикселей, Enter в активном поле и подписей не на английском закрывается **участием человека**, а не распознаванием любого экрана. Ввод текста тоже требует подтверждения: перевод строки или автоматически отправляющее поле может отправить сообщение. Вставка спрашивает даже без зарегистрированного чтения секрета; после распознанного чтения учётных данных сохраняется точная причина `paste_after_secret`. Для остальных непрозрачных действий GUI причина — `screen_action`.
46
+
47
+ Исключение из этого правила — одно точное сочетание выделения всего или копирования (`cmd+a`, `cmd+c`, `ctrl+a`, `ctrl+c`, с поддерживаемыми синонимами модификатора) в одном известном поле клавиш. Лишние поля, последовательности, некорректные массивы, перевод строки в конце и слишком длинные значения требуют подтверждения. Проверки видимых секретов сохраняются. Известные универсальные контроллеры (`computer`, `screen_control`, `desktop_control`, `browser_control`) спрашивают при неизвестном или отсутствующем действии. Полностью известная операция наблюдения, например `screenshot` или `get_screen`, освобождается от правила, только если указан один аргумент `action`. Имена операций в camelCase, с точками и дефисами нормализуются. Названный пользователем или разрешённый политикой адресат не разрешает действия GUI.
48
+
49
+ Последний список элементов каждого сервера (Playwright `[ref=e14]`, `[ref_14]`, номера и JSON-узлы) нужен только для объяснения. Другой формат больше не обходит подтверждение; его пример полезен для улучшения объяснений, но не нужен для блокировки клика. В запрос попадает каноническое английское слово стража, если оно распознано, а не исходная подпись с экрана. Перед одобрением проверьте реальное окно, цель, буфер обмена и ожидаемый эффект. В stdio-прокси каждое действие требует отдельной принятой формы MCP elicitation с установленным флажком; при отсутствии формы, отказе или отмене сервер действие не получает. Хук Claude возвращает `ask` клиенту; исполнение этого решения зависит от механизма разрешений клиента.
50
+
51
+ В строгом режиме подтверждений станет больше, в том числе для обычной навигации и клика в тело письма; удобство и усталость от подтверждений не измерялись. `audit` пишет журнал без блокировки, `off` выключает проверки. Нужны ранее зарегистрированные недоверенные данные (скриншоты по умолчанию недоверенные); если оператор пометит все наблюдения как private, этот триггер может исчезнуть. Проверяются распознанные имена операций, а не произвольно переименованные инструменты, исполнители JavaScript или скрытое поведение вредоносного сервера. На этих границах нужны политика оператора и изоляция ОС. OCR и классификатор инструкций в изображениях не добавлены: инъекция только в пикселях всё ещё может изменить ответ без проверяемого вызова. Локальные тесты hooks и настоящего stdio-прокси проверяют отказ до отправки, отдельное одобрение каждого действия и четыре заявленных случая. Эти локальные изменения ещё не развёрнуты и не опубликованы в npm.
52
+
53
+ Последний снимок теперь уточняет объяснение тремя способами. Координаты (`x`/`y`, `coordinate`, `coordinates` или `position`) сопоставляются с единственным JSON-элементом через `bounds`, `boundingBox`, `bounding_box` или `rect`: конечные числа в `{x,y,width,height}` либо `{left,top,right,bottom}`, размеры положительные. Правая и нижняя границы не включаются; `center` совпадает только при точном равенстве координат. Перекрытия, противоречащие прямоугольники или ссылки, некорректные числа и массивы с неоднозначным порядком xywh/xyxy не дают предполагаемой цели. Пересчёт между координатами экрана, страницы и масштабом не угадывается. Совпадение относится к геометрии прошлого снимка, а не к проверенной текущей цели.
54
+
55
+ Для Enter/Return однозначный узел `focused: true` либо `focusedRef`/`focusedElementId`/`activeElementId` уточняет активный элемент. У явно однострочного поля (`multiline: false`) в форме с единственным распознанным элементом отправки появляется объяснение «Enter может отправить форму»; у многострочного — для cmd/ctrl+Enter. Связь с формой задаётся `form`/`formId` или вложенностью JSON-формы. Отсутствующий или противоречивый фокус, неизвестная многострочность, разные формы и несколько кандидатов на отправку не позволяют сделать такой вывод. Распознанные accessibility/automation identifiers и `type: "submit"` дают каноническую подсказку действия даже без видимой подписи. Небольшие словари поясняют распространённые подписи Senden, Envoyer, Enviar, Wyślij и другие. Идентификатор, роль и перевод остаются недоверенными подсказками; исходное поле accessibility-id не копируется в дополнительные метаданные и не выводится в запросе разрешения; прежние ссылки и подписи элементов остаются в состоянии сессии.
56
+
57
+ Эти дополнения улучшают только объяснения; метаданные экрана не разрешают действие. Подтверждение только после вставки или ввода пропустило бы заранее заполненные сообщения, платежи и удаление. Геометрия, фокус или accessibility-id из одного снимка не доказывают безвредность навигации. Новый снимок только с изображением очищает подсказки; противоречивые дубликаты узлов не используются. Тесты hooks и stdio проверяют объяснения и отказ до отправки вызова серверу.
58
+
59
+ ## Регрессии Gautam: коды символов, НАТО, Git-метаданные и CI
60
+
61
+ Ограниченный декодер теперь распознаёт списки десятичных кодов символов и написание словами НАТО. Для кодов нужны не менее пяти допустимых скаляров, для НАТО — пяти явных единиц. Разделители: пробелы, запятые, точка с запятой, вертикальная черта и переводы строк. Неизвестная единица, недопустимый код или неоднозначный маркер регистра прерывают цепочку. Поддерживаются alfa/alpha, juliett/juliet, xray/x-ray, цифры словами/литералами, названия знаков и явные capital/uppercase/lowercase. Числовые JSON-массивы из 5–4096 целых тоже проверяются. Действуют прежние пределы глубины/вариантов/текста; исчерпание означает `payload_incomplete`. Нет eval и распаковки произвольных данных.
62
+
63
+ Само декодирование не означает утечку: запрет секрета требует совпадения с известным шаблоном или отпечатком. Обычные списки чисел и текст со словами НАТО автоматически не запрещаются. Первые 1–4 символа защищены границей учётных данных, даже если они слишком коротки для декодирования. Тесты проверяют восстановленные ключи и безвредный текст, не объявляя любое короткое совпадение секретом.
64
+
65
+ MCP без меток: `git_push`, `push_files`, `git_commit`, создание коммита и распространённые camelCase/точечные варианты теперь считаются отправкой или сохранением с возможной публикацией. Commit message может уйти наружу позже. `get_commit` / `list_commits` остаются чтением. Метки оператора по-прежнему требуют правильной настройки; независимая граница учётных данных покрывает и ошибочно помеченные MCP-инструменты. Shell Git сохраняет свои проверки. Для этих тестов реальные commit/push не выполнялись.
66
+
67
+ **Локальное изменение release-гейта:** `npm run build && npm run test:redteam` запускает весь сквозной hook replay с `--check`. Сохранены исходные 23 сценария и добавлены пять от Gautam: **28 случаев, из них 26 атак через инструменты требуют ask/deny, две атаки только на ответ — note/recheck**. Удалённый/повторённый сценарий, неверный исход или вновь открытая автоматическая передача дают ненулевой exit code. Тесты намеренно портят отчёт и проверяют отказ гейта. Команда включена в матрицу CI WARDEN, CI workspace, npm `prepublishOnly` и registry workflow до публикации. Это правки локальных файлов: удалённые CI, релиз и публикация не запускались. Заметка об ответе не доказывает, что модель не выполнит атаку только на ответ.
68
+
69
+ Повторить: `npm run build`, `npm run test:redteam` либо `node scripts/redteam/flow-redteam.mjs /tmp/warden-redteam.json --check`. Код: `test/flow-guard-gautam.test.ts`, `scripts/redteam/flow-gate.mjs`.
70
+
71
+ ## Ограниченный режим задач: меньше подтверждений, контроль реального действия
72
+
73
+ Строгий GUI остаётся по умолчанию. Старые `gui.mode: "policy"` / `gui.allow` читаются для миграции, но больше не разрешают клик, ввод или навигационную клавишу после внешнего текста. Страница может подделать даже точный origin, роль и accessibility ID. Геометрия, фокус и переводы служат только объяснением. Составное имя вроде `press_keys_then_execute` не получает исключение Copy. Дополнительные поля RPC не дают автоматического разрешения.
74
+
75
+ Новый встроенный адаптер задач (`node dist/mcp-server.js task`) сам обеспечивает ограничения. Это MCP-сервер для фиксированных ресурсов и HTTP-операций, а не ослабление проверки произвольных экранных инструментов. Он читает закреплённые локальные UTF-8-снимки без выполнения HTML/JS и исполняет проверенную операцию по ID. Модель не задаёт URL, метод, заголовки, тело, получателя, вложения или путь. У адаптера нет профиля браузера, cookies, системного буфера обмена, скриптов страницы, service workers, подпроцессов и произвольной переадресации инструментов. Обычный GUI сохраняет подтверждения. Это структурированный путь для поддерживаемых задач, а не изоляция произвольного браузера/VM.
76
+
77
+ **Настройка только оператором:** сохраните манифест ниже в `<WARDEN_STATE_DIR>/task-manifest.json`, политику — в пользовательский flow policy. Замените путь снимка, его хеш и endpoint; установите `expiresAt` не дальше 24 часов. В снимке должны быть только данные, которые вы намеренно открываете агенту. Пример хеша соответствует точным байтам `The public release is ready.\n`. Проверьте каждый запрос и вычислите `manifestSha256` по фактическим байтам файла со всеми пробелами и переводами строк. Хеш примера policy соответствует показанному манифесту с одним завершающим переводом строки. Разрешения автоматически не устанавливаются.
78
+
79
+ ```json
80
+ {
81
+ "version": 1,
82
+ "taskId": "public-report",
83
+ "expiresAt": "2026-10-23T23:00:00.000Z",
84
+ "resources": [
85
+ {
86
+ "id": "report",
87
+ "title": "Public report",
88
+ "path": "/absolute/path/public-report.txt",
89
+ "sha256": "1403cece199725b166f0f6e59faa9d45e3d5a25db26080fecf95e818ac8d4d0d"
90
+ }
91
+ ],
92
+ "operations": [
93
+ {
94
+ "id": "send_report",
95
+ "title": "Send reviewed report to Bob, no attachments",
96
+ "maxUses": 1,
97
+ "request": {
98
+ "method": "POST",
99
+ "url": "https://mail.example/api/send",
100
+ "headers": {
101
+ "content-type": "application/json",
102
+ "idempotency-key": "public-report-once"
103
+ },
104
+ "body": "{\"to\":\"bob@corp.com\",\"body\":\"The public release is ready.\",\"attachments\":[]}"
105
+ }
106
+ }
107
+ ]
108
+ }
109
+ ```
110
+
111
+ ```json
112
+ {
113
+ "mode": "ask",
114
+ "taskAdapter": {
115
+ "mode": "capabilities",
116
+ "server": "warden_task",
117
+ "manifestSha256": "1531d08beffb7c86d6f236c3bdfa85a8fbac1c3e8734d701e79455c53d0d94b7"
118
+ }
119
+ }
120
+ ```
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "warden_task": {
125
+ "command": "node",
126
+ "args": [
127
+ "/absolute/path/warden/dist/mcp-server.js",
128
+ "task"
129
+ ],
130
+ "env": {
131
+ "WARDEN_STATE_DIR": "/absolute/state/warden",
132
+ "WARDEN_FLOW_POLICY": "/absolute/state/warden/flow-policy.json"
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ```sh
140
+ node -e 'console.log(new Date(Date.now() + 3600000).toISOString())'
141
+ node --input-type=module -e 'import {createHash} from "node:crypto"; import {readFileSync} from "node:fs"; console.log(createHash("sha256").update(readFileSync(process.argv[1])).digest("hex"))' /absolute/state/warden/task-manifest.json
142
+ ```
143
+
144
+
145
+ Зарегистрируйте MCP-сервер **`warden_task`**: команда `node`, аргументы `[/absolute/path/warden/dist/mcp-server.js, task]`, те же `WARDEN_STATE_DIR` / `WARDEN_FLOW_POLICY`, что у hooks или `wrap --flow warden_task`. Это имя политики можно связывать только со встроенным адаптером WARDEN. Привязка к постороннему серверу передаст ему полномочия: имя инструмента и `readOnlyHint` не подтверждают подлинность. Отсутствующая, строгая или ошибочная политика запрещает сетевые операции; глобальные `deny`, `audit`, `off` тоже не дают их исполнять. Отдельные разрешения клиента могут по-прежнему запрашиваться.
146
+
147
+ Вызовы: `task_list {}`, `task_read {"id":"report"}`, `task_execute {"id":"send_report"}`. В аргументах допускается только фиксированный ID; лишние поля, дубликаты ключей JSON, массивы и скрытые метаданные RPC отвергаются. Запись hook `task_adapter_delegated` означает передачу доверенному исполнителю, а не успешное выполнение или подтверждение человека. Runtime повторно проверяет хеш, схему, срок и policy; блокировка между процессами и fsync расходуют бюджет до отправки. Бюджет сохраняется после перезапуска, изменённый манифест не сбрасывает уже использованный task ID. Ошибка/неизвестный исход и отмена после отправки расходуют разрешение; отмена до отправки — нет. Повреждённое состояние или оставшийся lock запрещают запуск. После неопределённого исхода оператор сверяет фактический результат, а не удаляет состояние ради повтора.
148
+
149
+ Поддерживаются только фиксированные HTTPS-запросы; `loopback-test` дополнительно разрешает HTTP на числовой localhost для изолированных тестов. Редиректы запрещены, cookies/ссылки/указания ответа не исполняются, размер ответа и полное время ограничены, повторов нет. `bearerEnv` — имя выбранной оператором переменной: токен добавляется только к фиксированному endpoint, не попадает в список операций или аудит. Аудит хранит ID и исходы без payload/токенов. Ответы остаются недоверенными данными.
150
+
151
+ **Платежи и транзакции:** заранее закрепите счёт, сумму, валюту и тело операции; используйте `maxUses: 1` и фиксированный `idempotency-key`, поддерживаемый провайдером. Одна отправка не гарантирует однократное зачисление. После таймаута/ошибки сначала сверяйте состояние у провайдера и только затем выдавайте новое разрешение. Интеграционные тесты используют loopback и синтетические ключи; реальных платежей не было.
152
+
153
+ **Пределы:** оператор доверяет процессу WARDEN и защищает его policy/state, runtime и привязку MCP. Проверенный запрос делает то, что реализует endpoint; даже GET не считается безвредным автоматически. Ошибочное разрешение оператора, явно разрешённый секрет в фиксированном теле, поведение сервера, скрытые каналы выбора ID/порядка/времени и обход защиты другими инструментами или клиентами вне этой границы. OCR и перехват произвольных действий живого GUI не добавлены.
154
+
155
+ **Проверка 2026-10-23:** заново выполнен детерминированный oracle replay AgentDojo 0.1.35 / v1.2.2 в локальном Docker без сети и API модели. Вариант intent: успешных доставленных атак действием 0/579; без вопроса 57/97 обычных задач; завершено 58/97; под атакой завершено 608/949 (исторически 613/949). `ask` считается отказом; это не доказывает безопасность целей без эталона и атак только на ответ. У AgentDojo нет GUI и инструментов адаптера — их проверяют отдельные stdio-, межпроцессные и loopback-тесты. Прежние запуски с живой моделью, 115 млн символов и HISTOR не повторялись. [Сводка replay](../scripts/agentdojo/results/summary-2026-10-23-local.json).
156
+
157
+ Регрессии: `test/task-adapter.test.ts`, `test/flow-guard-gui-policy.test.ts`, `test/flow-guard-credential-boundary.test.ts`, `test/flow-guard-secret-regression.test.ts`. Проверяются подделка подписей/ID, схема policy, закрепление ресурсов, конкуренция/перезапуски, редиректы, точные получатель/тело и первые 1–4 символа ключа в raw, hex, base64, Unicode и неизвестных кодировках. Неоднозначные короткие совпадения требуют проверки без ложного утверждения «обнаружен секрет».
158
+
159
+ ## Нативный бэкенд macOS: AppKit внутри приложения
160
+
161
+ **Реализовано:** Swift-пакет [WardenDesktop](../native/macos/Package.swift), `WardenDesktopSurface` и `WardenDesktopStandardIO` работают внутри нативного приложения — владельца окна. `warden-desktop --demo` открывает настоящее окно AppKit с локальным обработчиком кнопки. Он не управляет чужими приложениями, не отправляет глобальные события мыши/клавиатуры и не выполняет сетевые операции или платежи. Строгое подтверждение wrap сохранено по умолчанию. Бэкенд включается явно и требует подключения приложения; это не универсальный desktop-инжектор.
162
+
163
+ Сборка и запуск из каталога WARDEN. Нужны macOS, Xcode command-line tools и активная сессия WindowServer. Сборка нацелена на macOS 13+ и архитектуру хоста arm64/x86_64; проверенной считается только архитектура записанного локального прогона. В пакет включены исходники, не готовый бинарник. Новых runtime-зависимостей npm нет:
164
+
165
+ ```sh
166
+ npm run build
167
+ npm run build:macos
168
+ node dist/mcp-server.js wrap --id macos-owned-app --flow native --screen-read screenshot --screen-atomic -- native/macos/.build/warden-desktop --demo
169
+ npm run test:macos
170
+ ```
171
+
172
+ Пример нативного действия: ссылки строковые. Альтернатива — только `x` и `y` в глобальных экранных points с началом сверху слева, не в пикселях. Перекрытые или неоднозначные цели отклоняются:
173
+
174
+ ```json
175
+ {"name":"click","arguments":{"index":"3"}}
176
+ ```
177
+
178
+ **Граница атомарности:** prepare удерживает точный `NSButton`, явный `NSObject`-target, selector и проверенную по ABI реализацию из `method_getImplementation`. Commit на MainActor сверяет ревизию, живые роль/ID/рамку/подпись, идентичность объекта, окно/фокус/модальность, прозрачность всей цепочки родительских views и hit-test. Полностью прозрачные кнопки/окна, заблокированное модальное окно и ожидающие sheet, включая переходную связь `sheetParent`, отклоняются. После hit-test свойства считываются заново; после проверки обоих часов и всех внедрённых callback выполняется последняя сверка ревизии. Закреплённый IMP вызывается через `NativeAction` в том же проходе главного цикла. `NSApp.sendAction` намеренно обходится: переопределение может отложить, перенаправить действие или вернуть успех без вызова согласованного метода. Нет `AXPress`, `CGEvent`, анимации `performClick`, first-responder поиска или отложенного координатного ввода. Поддерживаются только зарегистрированные видимые активные momentary push buttons с сигнатурой `void action(id sender)`. Прямой клик, текст, аккорды, буфер обмена, secure-поля, незарегистрированные views и внешние PID отклоняются.
179
+
180
+ **Подключение:** импортируйте локальный Swift-пакет в приложение. На MainActor создайте `WardenDesktopSurface(window:applicationID:)`, задайте кнопке accessibility element/role/identifier и вызовите `register(id:button:target:selector:)`. Храните surface и `WardenDesktopStandardIO(surface:)` на всё время работы; `start()` обслуживает выделенный унаследованный stdio-канал. Наблюдение возвращает структурированные метаданные зарегистрированных контролов, а не пиксельный снимок или глобальное AX-дерево. Максимум 64 контрола, уникальные ссылки/ID и явные удерживаемые target; nil-target и небезопасные Objective-C сигнатуры запрещены. См. [исходник](../native/macos/Sources/WardenDesktop/NativeSurface.swift) и [нативный пример](../native/macos/Sources/WardenDesktopHost/Main.swift).
181
+
182
+ Все изменения модели, получателя и обработчика должны выполняться на MainActor с вызовом `invalidate()` **до** изменения вне одобренного обработчика, включая невидимые изменения и A → B → A. Уведомления окна и свежие отпечатки дополняют это правило, но не доказывают учёт всех скрытых изменений модели. Одобренные обработчики должны быть синхронными, без вложенного модального run loop, асинхронной пересылки и подмены responder. Их собственные изменения покрываются сменой ревизии commit. Если приложение не соблюдает этот контракт владения, атомарный режим включать нельзя. Для стороннего приложения без подключения нет запасного пути: Apple предоставляет [раздельные AX-чтение и действие](https://developer.apple.com/documentation/applicationservices/1462091-axuielementperformaction), а не наш контракт ревизии.
183
+
184
+ Билеты связывают полные аргументы и истекают и по системным, и по монотонным часам, максимум через пять минут. Они расходуются до вызова; отмена, повтор, перезапуск и несовпадение не дают использовать билет снова. Ошибка/неопределённость вызова блокирует нативный экземпляр; нельзя перезапускать его или выдавать новое одобрение лишь ради повтора платежа. Квитанция committed подтверждает локальный вызов target-обработчика, **не** доставку письма, завершение платежа или асинхронной работы. Для этого нужны сверка транзакции и постоянный idempotency key конечного сервиса. При потере ответа wrap сохраняет блокировку неопределённого результата.
185
+
186
+ **Нативный интеграционный гейт:** `npm run test:macos` отдельно собирает production/test-бинарники и проверяет настоящие окна и stdio/wrap-диалоги. Покрыты изменения цели/обработчика/рамки/окна, замена объекта с прежним видом, ABA, реентерабельность hit-test, срок/откат часов/повтор/перезапуск/отмена, совместимость отпечатков между языками и многоязычные подписи. Тестовые методы изменения отсутствуют в production-сборке. Набор отделён от кроссплатформенного `npm test`; другая ОС, отсутствие инструментов или GUI приводят к ошибке нативного гейта, без тихого skip. В локальную конфигурацию CI добавлен macOS-гейт; удалённо он не запускался. Тесты не запрашивают глобальные Accessibility/Screen Recording-разрешения и не меняют TCC. Публикации/деплоя нет.
187
+
188
+ **Повторный локальный аудит (2026-10-24):** prepare и commit теперь заново считывают нативные свойства после `hitTest`; изменение обработчика, подписи, доступности или рамки приводит к отказу, даже если приложение пропустило `invalidate()`. Оба времени проверяются ещё раз непосредственно перед отправкой действия. Аргумент отправителя Objective-C должен быть именно объектом (`@`), а не блоком (`@?`). Общий атомарный TypeScript-сервер также использует монотонный срок и повторно проверяет истечение перед эффектом. Регрессии охватывают эти случаи, изменение цели при prepare, освобождение ёмкости просроченных разрешений и повторный вход в нативный обработчик. Это дополнение к договору владения: getters и hit-test не должны запускать вложенные циклы событий или побочные действия; скрытые изменения модели/получателя по-прежнему требуют предварительного invalidate. Поддерживаются только доверенные приложения, подключившие бэкенд.
189
+
190
+ **Контракт прямого вызова (второй локальный аудит, 2026-10-24):** зарегистрированные обработчики должны безопасно вызываться напрямую и самостоятельно проверять права приложения; нельзя полагаться для этого на переопределение `NSApplication.sendAction` или маршрутизацию responder. Провайдеры часов и getters — доверенный синхронный код хоста. Скрытые изменения и ABA по-прежнему требуют предварительного `invalidate()`. Регрессии покрывают модальность/прозрачность во время hit-test, смену runtime-реализации, неизменно полупрозрачную кнопку, перехват dispatch и invalidation из последнего callback часов. Эти проверки входят в npm `0.21.0`. Локальный отчёт тестов не заменяет подписанное release-quality подтверждение. Его текущий digest охватывает JavaScript-файлы `dist`, а не исходники нативного SDK; нативная проверка отдельная.
191
+
192
+ ## Атомарная проверка цели на сервере
193
+
194
+ **Явное включение:** `--screen-atomic` требует `--flow`, `--screen-read` и принудительного режима flow. Строгое подтверждение остаётся по умолчанию. Нужен доверенный сервер с поддержкой контракта; аннотации инструментов и заявленная версия протокола не доказывают доверие. Неподдерживаемый сервер приводит к отказу до вопроса пользователю. Запасного обычного клика нет. Прежний режим только со снимками остаётся неатомарным.
195
+
196
+ Сначала соберите WARDEN, затем запустите локальный пример из его каталога. Пример владеет виртуальной формой: он не управляет ОС, не отправляет письма, не проводит платежи и не обращается к сети:
197
+
198
+ ```sh
199
+ node dist/mcp-server.js wrap --flow screen --screen-read screenshot --screen-atomic -- node examples/atomic-screen-server.mjs
200
+ ```
201
+
202
+ **Протокол:** до вопроса прокси приватно вызывает `warden/screen/prepare` с точным действием и настроенным наблюдением. Пример параметров:
203
+
204
+ ```json
205
+ {
206
+ "protocol": "warden.screen.atomic.v1",
207
+ "observation": { "name": "screenshot", "arguments": {} },
208
+ "action": { "name": "click", "arguments": { "index": 3 } }
209
+ }
210
+ ```
211
+
212
+ Сервер возвращает `protocol`, непрозрачный одноразовый `ticket`, ревизию поверхности `revision`, отпечаток цели `stamp`, `expiresAt` и `observation`. Прокси сверяет отпечаток с наблюдением, показывает действие и после явного принятия повторно проверяет определения инструментов, риск-контекст и свежую цель. Вместо обычного вызова отправляется `warden/screen/commit` с `{protocol,ticket,expected:{revision,stamp},action}`. Сервер расходует билет, сравнивает текущую ревизию, разрешённую цель и точные аргументы и синхронно выполняет действие в той же критической секции. Между проверкой и эффектом нельзя уступать цикл событий или ставить координатный клик в очередь. Любое изменение, включая обработчик/получателя и A → B → A, должно менять ревизию. Действие использует уже разрешённую ссылку на цель, без повторного поиска по координатам.
213
+
214
+ На сервере используйте `AtomicScreenServer` из `@aimarket/warden/atomic-screen` (в локальной сборке — `dist/atomic-screen.js`). Три метода протокола направляйте в `prepare(params)`, `commit(params)` и `cancel(params)`, инструмент наблюдения — в `read()`. Все прямые пути выполнения действий должны отказывать. Нужен один общий экземпляр на поверхность для всех соединений; остальные изменения проходят через `replace(snapshot)`. Доверенный синхронный `apply(action, target)` возвращает `{result,snapshot}`, где result — обычный результат MCP-инструмента. Асинхронные функции запрещены; исключение или неверный результат блокируют поверхность до явной сверки и замены состояния. См. [работающий пример сервера](../examples/atomic-screen-server.mjs).
215
+
216
+ Билеты действуют не больше пяти минут, связывают полное действие, расходуются при попытке commit и не переживают перезапуск сервера. Лимит — 256 ожидающих билетов. Клиент не может вызвать приватный протокол через wrap; билеты не передаются модели и в flow-журнал. `warden/screen/cancel` удаляет неиспользованный билет после отказа/отмены; забытые билеты ограничены сроком. Аргументы атомарного действия должны полностью помещаться в 1500 экранированных символов подтверждения; длинные вызовы отклоняются вместо обрезки.
217
+
218
+ Проверенная квитанция `committed` содержит `protocol,status,revisionBefore,revisionAfter,stamp,result`; wrap возвращает только `result`. Проверенная квитанция `refused` содержит `protocol,status,reason` и означает отсутствие эффекта. В аудите — `atomic_committed` / `atomic_refused`. Повреждённая квитанция, ошибка транспорта или потерянный результат — `execution_uncertain`: повтор запрещён, общая GUI-блокировка остаётся до сверки оператором. Эффект мог произойти до потери ответа. Серверный билет не заменяет постоянный платёжный idempotency key.
219
+
220
+ **Граница владения:** гонка закрывается только для поверхности, чьё полное состояние и синхронное действие контролирует доверенный сервер. Аутентификация или выделенный транспорт должны допускать к prepare/commit только доверенные прокси; билет сам по себе не доказывает согласие человека. Один экземпляр в процессе не является межпроцессной блокировкой ОС. Блокировка сервера вокруг асинхронного ввода мыши или обёртка над Playwright/desktop RPC не делают удалённый экран атомарным. Нативному бэкенду нужна реальная транзакция платформы/ревизия либо управляемая синхронная модель приложения. Нативный модуль AppKit описан в разделе macOS; сторонние приложения без его подключения не поддерживаются. Ложные метаданные, неучтённые внешние изменения и вредоносные разрешённые обработчики не покрываются гарантией. Claude hook не может выполнить приватный commit после одобрения. Регрессии проверяют изменение после последнего чтения прокси, ABA/обработчик, повтор, срок, перезапуск, реентерабельность, запрет прямого клика и неопределённый эффект. Публикации/деплоя нет.
221
+
222
+ ## Auten: одно подтверждение результата и свежий экран после одобрения
223
+
224
+ **Подтверждение результата:** добавьте фрагмент `runs` ниже в существующий закреплённый манифест, сохраните JSON с отступом в два пробела и завершающим переводом строки, пересчитайте хеш и используйте следующую policy с `taskAdapter.mode: "review"`. Вызов — `task_run {"id":"mail_to_bob"}`. Встроенный адаптер задаёт один вопрос через MCP form elicitation до первого действия: результат, полный порядок запросов, точные URL и тела. Учётные данные заголовков скрыты. Флажок по умолчанию выключен. Отсутствие формы, принятие значений по умолчанию, отказ или отмена ничего не разрешают. `strict` остаётся режимом по умолчанию, `capabilities` сохраняет явное разрешение оператора.
225
+
226
+ В примере подготовка/отправка GUI сведена к фиксированному HTTP-действию. План поддерживает до восьми различных ID операций; максимум 16 планов, полное экранированное описание — до 12 000 символов. Модель не может менять шаги, порядок, получателя, тело или результат. В `review` отдельный `task_execute` запрещён, чтобы вопрос нельзя было обойти. Чтение ресурсов и списка не требует вопросов; отдельные разрешения клиента и sensitive-tool policy могут по-прежнему запрашиваться.
227
+
228
+ Адаптер держит межпроцессную блокировку задачи на время вопроса и исполнения, проверяет доступность бюджета до вопроса, после принятия атомарно резервирует весь план и бюджеты всех операций. План одноразовый и после перезапуска. Перед каждым шагом повторно проверяются манифест/policy, срок, отмена и привязка учётных данных. Изменение контекста, ошибка или неопределённый ответ останавливают оставшиеся шаги; неиспользованные резервирования тоже расходуются. Уже выполненные действия не откатываются. Ответ сервера не может менять следующий шаг или адрес. Отказ/отмена до резервирования не расходуют план. Не удаляйте неопределённое состояние/lock ради повтора платежа — сначала сверяйте результат. Аудит отдельно хранит одобрение, резервирование, завершение и остановку без payload/токенов.
229
+
230
+ ```json
231
+ {
232
+ "runs": [
233
+ {
234
+ "id": "mail_to_bob",
235
+ "title": "Send the reviewed public report to bob@corp.com in Mail",
236
+ "operations": [
237
+ "send_report"
238
+ ]
239
+ }
240
+ ]
241
+ }
242
+ ```
243
+
244
+ ```json
245
+ {
246
+ "mode": "ask",
247
+ "taskAdapter": {
248
+ "mode": "review",
249
+ "server": "warden_task",
250
+ "manifestSha256": "c69bafc53aa2e4a1a82dd9a20accbe2e4de5372d7545509fe3f6ccf18fdc5580"
251
+ }
252
+ }
253
+ ```
254
+
255
+ **Свежий экран — только в wrap:** явно выберите инструмент наблюдения того же проверенного сервера, например:
256
+
257
+ ```sh
258
+ node dist/mcp-server.js wrap --flow screen --screen-read get_elements -- node /absolute/path/screen-server.js
259
+ node dist/mcp-server.js wrap --flow screen --screen-read computer --screen-read-input '{"action":"screenshot"}' -- node /absolute/path/screen-server.js
260
+ ```
261
+
262
+ `--screen-read` требует `--flow`; `--screen-read-input` — строгий JSON: пустой ввод для известного инструмента наблюдения либо одно известное поле `action` для общего контроллера. `readOnlyHint` не даёт полномочий. Без этой настройки остаётся обычное строгое подтверждение каждого GUI-вызова, без заявления о проверке после одобрения. У Claude hook нет обратного вызова между диалогом клиента и выполнением, поэтому он эту проверку не делает.
263
+
264
+ При включении wrap читает исходное состояние прямо перед вопросом, затем после принятия повторно проверяет определения и читает экран ещё раз. Проверяется именно новый ответ, а не кэш. Он должен однозначно задавать цель, роль, точную ссылку узла, рамку, контекст и согласованный фокус для клавиатуры; при наличии сравниваются accessibility ID, подпись и подсказки формы. Изменение, отсутствие, перекрытие/неоднозначность, неполный список, одни пиксели или ошибка чтения запрещают действие. Масштаб и систему координат не угадываем. Неподдерживаемая схема нескольких действий/лишних полей не проходит сравнение. Изменившийся риск или вновь обнаруженный секрет тоже останавливают вызов. Отмена во время последнего чтения учитывается.
265
+
266
+ Известные GUI-действия разных прокси с общими `WARDEN_FLOW_SESSION` / state сериализуются экранной блокировкой, в том числе если второй прокси не включает перепроверку. Обычный результат снимает lock; пропавший результат/сбой оставляет неопределённую блокировку для проверки оператором. Наблюдения без изменения UI могут продолжаться. `screen_validation` пишет `unchanged`, `refused_without_approval`, `refused_after_approval` или `execution_uncertain`; принятие формы и совпадение метаданных сами по себе не означают выполнения.
267
+
268
+ **Предел:** окно устаревшей цели сужается, но снимок и клик не становятся атомарными. Внешний процесс может изменить UI после чтения; сервер — вернуть старые/ложные данные; одинаковые ID/рамки не доказывают неизменность обработчиков или безвредность действия. Полное закрытие требует доверенного сервера, который проверяет revision/цель и выполняет действие атомарно. Произвольная цепочка click/paste/Send не получает общее разрешение. Группировка относится к структурированному адаптеру с контролем исполнения, а не к доверию метаданным страницы. Атаки только на ответ остаются вне контроля действий инструментов.
269
+
270
+ Локальные регрессии: `test/wrap-screen.test.ts`, `test/wrap.test.ts`, `test/task-adapter.test.ts`. [Новый локальный AgentDojo checkpoint](../scripts/agentdojo/results/summary-2026-10-23-auten-local.json): детерминированный replay без API модели и GUI-инструментов. Публикации, деплоя и отправки комментария не было.
271
+
5
272
  ## Объяснения запросов разрешения (исходники, ещё не выпущены)
6
273
 
7
274
  Сообщение теперь показывает действие и до четырёх адресатов: например, `Action: mcp__slack__send_message. Targets: channel="#general".` Далее указана причина запроса. Перечень инструментов, давших внешний текст, — контекст сессии, а не доказательство происхождения адресата. Происхождение каждого адресата пока не отслеживается.
@@ -20,20 +287,21 @@
20
287
  - Защищены распознанные записи в политику/состояние стража, настройки hooks Claude и Git hooks/config, включая раскрываемые переменные путей и симлинки. Hooks с правами самого агента не заменяют ограничения ОС.
21
288
  - Хост разбирается URL-парсером; userinfo не считается хостом. Проверяются все найденные адресаты и наличие аргумента назначения. Ссылка в теле письма не разрешает его получателя. Почтовые адреса в политике сопоставляются целиком; домен не разрешает все ящики. Упоминание адресата пользователем — грубое исключение, а не разрешение любых действий и данных.
22
289
  - Контакты разрешаются только через явно заданный `contactTools` с меткой `private`: структурированные записи `name`/`email`, в том числе JSON в MCP-ответе. В запросе пользователя должно быть полное отображаемое имя; неоднозначное имя требует подтверждения. Файлы проекта, произвольный текст, YAML и старый кэш контактов не подходят. Доверяйте только справочнику, записи которого агент и посторонние не могут менять.
23
- - Отпечатки проверяют видимый текст аргументов и ограниченный набор декодирований URL/base64/hex. С 2026-10-22 значения, похожие на ключи (случайные последовательности в файлах с секретами и известные форматы токенов, где бы их ни прочли), снимаются ещё и окнами по 8 букв и цифр, для hex-ключей — по 10: кусок ключа, ключ задом наперёд, с разделителями или невидимыми символами, кусками в base64 или с кириллическими или греческими буквами-двойниками запрещается. Это самые маленькие размеры, при которых ни один из 480 выдуманных ключей восьми форматов ни разу не совпал с 115 млн букв и цифр (этот монорепо и 1 000 пакетов HISTOR) обычного текста; части, общие для всех ключей одного вида (идентификатор алгоритма в DER-ключе, заголовок и поля JWT), не снимаются вовсе. Каждый аргумент помнит хвост того, что он отправил после внешнего текста, поэтому куски, отправленные подряд через один аргумент, проверяются целиком. Куски короче 8 символов, каждый раз обёрнутые другими словами, по-прежнему проходят, как и начальный формат ключа (`rk_live_`). Отпечатки не читают произвольные файлы в момент отправки и не покрывают все кодировки и схемы MCP. Правки внутри проекта обычно разрешены; исполнение кода проверяется отдельно.
290
+ - Отпечатки проверяют видимый текст аргументов и ограниченный набор декодирований URL/base64/hex. С 2026-10-22 значения, похожие на ключи (случайные последовательности в файлах с секретами и известные форматы токенов, где бы их ни прочли), снимаются ещё и окнами по 8 букв и цифр, для hex-ключей — по 10: кусок ключа, ключ задом наперёд, с разделителями или невидимыми символами, кусками в base64 или с кириллическими или греческими буквами-двойниками запрещается. Это самые маленькие размеры, при которых ни один из 480 выдуманных ключей восьми форматов ни разу не совпал с 115 млн букв и цифр (этот монорепо и 1 000 пакетов HISTOR) обычного текста; части, общие для всех ключей одного вида (идентификатор алгоритма в DER-ключе, заголовок и поля JWT), не снимаются вовсе. Каждый аргумент помнит хвост того, что он отправил после внешнего текста, поэтому куски, отправленные подряд через один аргумент, проверяются целиком. Локальный код 2026-10-23 добавляет описанные выше сопоставление пар по шесть символов и декодирование явных списков символов. Начальный формат (`rk_live_`) сам по себе секретом не считается. Отпечатки не читают произвольные файлы в момент отправки и не покрывают все кодировки и схемы MCP. Правки внутри проекта обычно разрешены; исполнение кода проверяется отдельно.
24
291
  - После внешнего текста запись ключа, прочитанного в сессии, в обычный файл проекта требует подтверждения (`deny` отказывает): файлы проекта потом коммитят и публикуют без нового вызова. `.env`, `.npmrc` и другие файлы с секретами — место для ключей, туда запись проходит; правка, которая только убирает ключ, не срабатывает.
25
292
  - Адрес, который есть в запросе только во вставленном тексте, в цитате (`>`), в заголовках вставленного письма или ниже пометки о пересылке, не считается названным: отправка на него спрашивает один раз. Точка или запятая после набранного адреса больше не мешают его узнать.
26
293
  - MCP-инструмент без метки оператора считается исходящим, если об этом говорит его имя (send, post, share …), если в аргументах есть URL или, с 2026-10-22, если он называет адресата: аргумент вроде `to`, `email`, `attendees`, `assignee`, `collaborator` или `username`, либо любой e-mail или IBAN. `warden-mcp flow-labels` показывает MCP-инструменты без меток, которыми пользовались ваши сессии, с догадкой стража и блоком `labels`, который нужно проверить и вставить в политику.
294
+ - По умолчанию после внешних данных распознанные действия управления экраном требуют подтверждения независимо от координат, текста скриншота, формата списка элементов и языка подписи. Это клики/тапы/перетаскивания, ввод и заполнение полей, вставка, Enter/Return и неизвестные нажатия клавиш. `deny` отказывает. Английские слова уточняют объяснение; привычная подпись вроде Inbox не разрешает клик. Подробности — в ограниченном режиме задач выше.
27
295
  - Инъекция, которая меняет только ответ, не делает вызова, которому можно отказать. С 2026-10-22 хук Stop плагина добавляет под ответом строку, если за этот ход читался внешний текст: какие источники, и отдельно — если какой-то из них обращался к ассистенту с указаниями. Если ответ повторяет 12 букв и цифр подряд из тех предложений, где внешний текст обращался к ассистенту, хук ещё и один раз возвращает ответ модели (`decision: block`) на проверку по запросу пользователя, прежде чем пользователь его прочтёт; пользователь теряет только время этой проверки. `answerNote`: `always` (по умолчанию), `instruction` (только этот случай) или `off`; вне плагина зарегистрируйте `warden-mcp hook stop`.
28
296
  - Прокси учитывает текст JSON-RPC errors и ошибки инструментов как внешние данные. Если учёт ответа не удался, ответ удерживается. Повреждённое состояние сессии блокирует проверяемый вызов вместо сброса в пустую сессию.
29
297
 
30
- Вышло в npm `0.17.0`: `npx -y @aimarket/warden@0.20.0 hook pre-tool-use`, либо из исходников — в каталоге WARDEN `npm ci && npm run build`, затем `node dist/mcp-server.js hook pre-tool-use`. Зарегистрируйте также prompt/post hooks либо плагин Claude.
298
+ Вышло в npm `0.17.0`: `npx -y @aimarket/warden@0.21.0 hook pre-tool-use`, либо из исходников — в каталоге WARDEN `npm ci && npm run build`, затем `node dist/mcp-server.js hook pre-tool-use`. Зарегистрируйте также prompt/post hooks либо плагин Claude.
31
299
 
32
300
  Политика: `~/.local/state/warden/flow-policy.json` или `WARDEN_FLOW_POLICY`. Режимы: `ask`, `deny`, `audit`, `off`; `audit` только пишет журнал. Пример настройки контактов и адресатов — в [английской версии](flow-guard.md).
33
301
 
34
302
  Прокси: `node dist/mcp-server.js wrap --flow mail -- node mail-server.js`. Всем прокси одной беседы задайте одинаковый новый `WARDEN_FLOW_SESSION`. По умолчанию используется PID родителя; разные запускатели могут иметь разных родителей. Прокси не видит запрос пользователя и встроенные инструменты клиента. Вызов, о котором нужно спросить, спрашивается через форму MCP elicitation клиента, если она есть (ответ пишется в журнал как `approvalOutcome`), иначе или с `--ask refuse` отклоняется. `trustedSources` применяется к URL WebFetch, а не к ссылкам в произвольных аргументах MCP.
35
303
 
36
- **Какую сборку описывают цифры.** Таблицу воспроизведения ниже прогнали заново 2026-10-22 на текущем коде: исправления аудита плюс изменения 2026-10-22. Изменения 2026-10-22 не поменяли в ней ни одного решения (все 1 046 записей совпали с кодом до них); исправления аудита стоили одной задачи без вопроса и 19 задач, выполненных под атакой. Таблицы прогона с моделью и стоимость по-прежнему относятся к коду до аудита, вплоть до коммита `2328be980`; нового прогона с моделью не было. Воспроизведение эталонной последовательности — один путь атаки, а не адаптивный худший случай; атаки со знанием кода от 2026-10-22 — [ниже](#что-меняли-2026-10-22-и-зачем).
304
+ **Какую сборку описывают цифры.** Таблицу воспроизведения ниже прогнали заново 2026-10-22 на коде того дня: исправления аудита плюс изменения 2026-10-22. Изменения 2026-10-22 не поменяли в ней ни одного решения (все 1 046 записей совпали с кодом до них); исправления аудита стоили одной задачи без вопроса и 19 задач, выполненных под атакой. Таблицы прогона с моделью и стоимость по-прежнему относятся к коду до аудита, вплоть до коммита `2328be980`; нового прогона с моделью не было. Воспроизведение эталонной последовательности — один путь атаки, а не адаптивный худший случай; атаки со знанием кода от 2026-10-22 — [ниже](#что-меняли-2026-10-22-и-зачем).
37
305
 
38
306
  ## Измерено на AgentDojo
39
307
 
@@ -189,12 +457,12 @@ Sonnet; в воспроизведении выше модели нет, а пр
189
457
  | MCP-инструмент без метки, называющий адресата, — исходящий; `warden-mcp flow-labels` | «добавить участника» с e-mail атакующего и «добавить соавтора» по имени пользователя проходили | оба спрашивают |
190
458
  | Хук Stop: строка под ответом, опиравшимся на внешний текст | инъекция только в ответ не делает вызовов | пользователь видит, на какие источники опирался ответ; ничего не блокируется |
191
459
  | Набор правил v15 (см. [gates](gates.ru.md)) | 78 отравленных инструментов из dev-половины MCPTox проходили правила | отложенная половина 171 → 194 из 218 (правила писали только по другой половине), dev-половина 189 → 233 из 267; 0 из 45 чистых серверов; корпус и 1 000 пакетов HISTOR блокируются ровно как при v14 |
192
- | Воспроизведение заново на текущем коде | исправления аудита от 2026-10-18 не измерялись | 0 из 579 атак-действий, 57 из 97 задач без вопроса, 608 из 949 выполнено под атакой; изменения 2026-10-22 не поменяли ни одного решения |
460
+ | Воспроизведение заново на коде 2026-10-22 | исправления аудита от 2026-10-18 не измерялись | 0 из 579 атак-действий, 57 из 97 задач без вопроса, 608 из 949 выполнено под атакой; изменения 2026-10-22 не поменяли ни одного решения |
193
461
  | `scripts/agentdojo/Dockerfile.dockerignore` | `.dockerignore` пакета исключает `dist/`, и команда из «Повторить» не собиралась | собирается |
194
462
 
195
463
  Эти три по-прежнему проходили: куски короче 10 символов в разных словах, адрес, вставленный в запрос, и ключ,
196
464
  записанный в файл проекта. В тот же день мы закрыли всё, что закрывается без ложных срабатываний, и написали ещё шесть
197
- атак против новых правил. Из 23 проходят 2.
465
+ атак против новых правил. В том релизе из 23 проходили 2.
198
466
 
199
467
  | Изменение | Зачем | Результат |
200
468
  |---|---|---|
@@ -206,7 +474,7 @@ Sonnet; в воспроизведении выше модели нет, а пр
206
474
  | Набор правил v16 (см. [gates](gates.ru.md)) | 34 отравленных инструмента dev-половины MCPTox всё ещё проходили, почти все — без входных параметров | отложенная половина 194 → 210 из 218, в том числе все 66 перехватов с неявным триггером; 0 из 45 чистых серверов; корпус и 1 000 пакетов HISTOR блокируются ровно как при v15; пять ложных срабатываний первого варианта закреплены в тестах |
207
475
  | Воспроизведение заново | новые проверки не должны спрашивать там, где не спрашивал 0.19.0 | все 1 046 записей совпадают с 0.19.0 |
208
476
 
209
- По-прежнему проходят ([результаты](../scripts/redteam/results/)):
477
+ В релизе 2026-10-22 эти два примера ещё проходили. В локальном коде 2026-10-23 оба блокируются; см. новый раздел выше. Исторические [результаты](../scripts/redteam/results/):
210
478
 
211
479
  - **Куски короче 8 символов, каждый в других словах**, на адрес, который набрал пользователь: 7 и больше писем на
212
480
  ключ из 40 символов.
@@ -227,10 +495,7 @@ Sonnet; в воспроизведении выше модели нет, а пр
227
495
  один раз просит модель его перепроверить; он видит только те указания, которые страж распознаёт как указания.
228
496
  - **Локальные изменения внутри проекта проходят**, кроме ключа, прочитанного в сессии и записанного в обычный файл.
229
497
  Править файлы проекта — работа агента.
230
- - **Утечка мелкими кусками.** Обычный приватный текст может уйти адресату, которого назвал пользователь, целиком или
231
- кусками: это выбор пользователя. Другим адресатам, а ключи и номера карт — кому угодно: куски, отправленные подряд
232
- через один аргумент, склеиваются; куски короче 8 символов с другими словами вокруг каждого — нет, как и ключ,
233
- продиктованный словами.
498
+ - **Утечка мелкими кусками.** Обычный приватный текст может уходить названному пользователем адресату. Потоковое склеивание и новое правило пар по шесть символов покрывают отдельные разбиения секретов; более короткие части с добавленным текстом и неподдерживаемые словесные кодировки остаются пределами.
234
499
  - **Вставленный текст — не набранный.** Адрес, который вы хотели использовать, но только вставили, спросит один раз.
235
500
  - **Он не видит** ваш запрос до установки плагина и текст, который модель держит из других мест.
236
501