Технический долг ИИ: почему AI-агенты и MCP-сервера требуют жесткого контроля зависимостей — ИИ для бизнеса

Технический долг ИИ: почему AI-агенты и MCP-сервера требуют жесткого контроля зависимостей

Прослушать статью

AI-агенты упрощают работу, добавляя слои делегирования. Эти слои становятся зависимостями, а зависимости — риском.

Митчелл Hashimoto советует перестать обновлять зависимости, что с исторической точки зрения звучит как безумие. Особенно после Mythos и потенциала сделать zero-day-эксплойты обычным явлением. И все же после того, что этой весной произошло в npm, совет Hashimoto может звучать уже не как ересь, а как контроль.

Его правило простое: форкать зависимости, оставлять только то, что вы реально используете, и не обновляться, пока что-то не сломается у ваших пользователей. В его логике не нужно обновлять пакет только потому, что GitHub Dependabot открыл pull request, или потому что вышла новая — якобы более безопасная — версия. А если вы все же обновляете, то ответственность за понимание каждого значимого коммита в транзитивном дереве лежит на вас, а не на сопровождающем пакета.

В индустрии, где «последнее» привыкли считать «безопасным», это звучит безрассудно — пока не посмотришь на то, что происходило этой весной. В двух самых тяжелых атаках на npm больше всего пострадали именно те, кто тянул свежие версии. Когда был скомпрометирован HTTP-клиент axios, злоумышленники выпустили две зараженные версии, которые устанавливали remote-access Trojan на каждую машину, сделавшую свежую установку в течение примерно трех часов. Если вы были зафиксированы на чистой версии и не переустанавливали пакет, вы это проспали. И это к лучшему. Через несколько недель, после зараженного релиза node-ipc, червь Mini Shai-Hulud самораспространялся через TanStack, а затем дошел до Mistral, UiPath и длинного хвоста пакетов, которые скачивают миллионы раз в неделю.

Как от этого защищаться?

Возможно, вообще ничего не делать. В конце концов, самым эффективным средством против Mini Shai-Hulud оказался не сканер и не сигнатура. Им оказался cooldown. StepSecurity задерживала новые версии на настраиваемое окно — примерно 10 дней — прежде чем отдавать их кому-либо. Клиенты на cooldown продолжали получать последнюю известную хорошую версию и вообще не подвергались риску, а остальной мир узнавал о проблеме уже постфактум.

Иными словами, сработала немодная — и исторически считавшаяся глупой — защита: не брать новую версию только потому, что она новая. Ирония в том, что ответом индустрии на разработку ИИ, похоже, стало добавление еще большего числа зависимостей. Что могло пойти не так?

Дерево зависимостей вышло из-под контроля package manager

Десятилетиями мы отдавали недифференцированную работу библиотекам, и в целом это хорошо. Никто не хочет, чтобы каждая команда вручную писала Transport Layer Security, парсинг дат, логирование и прочее — разве что человек, который компилирует Gentoo ради удовольствия. (Мы знаем, кто вы!) Open source работает потому, что мы специализируемся и делимся.

Но обмен означает, что мы также заимствуем друг у друга package manager’ы, аккаунты сопровождающих, CI/CD-пайплайны, скрипты релизов и так далее. Чудо современного ПО в том, что маленькая команда может собрать мировой продукт из тысячи компонентов, которые она не писала. Но в этом же и риск.

ИИ усиливает этот риск, потому что дерево зависимостей больше не ограничено кодом.

Coding agent не просто импортирует пакеты: он также читает инструкции репозитория, следует system prompts, выбирает инструменты, обращается к Model Context Protocol (MCP)-серверам и выполняет shell-команды. Каждая такая способность — еще одна зависимость от поведения, которое живет вне модели. Часть этого, конечно, полезна, но все это увеличивает поверхность атаки.

Достаточно взглянуть на исследование 117 062 изменений зависимостей в семи экосистемах: исследователи Purdue обнаружили, что AI-агенты выбирали заведомо уязвимые версии пакетов чаще людей — в 2,46% случаев против 1,64%. Ошибки агентов было и труднее исправить: в 36,8% случаев для устранения проблемы требовалось обновление до major-версии, тогда как у людей — в 12,9% случаев. В сумме работа над зависимостями с участием агентов дала чистый прирост 98 уязвимостей, тогда как работа, выполненная людьми, дала чистое сокращение на 1 316. Агенты еще и придумывают несуществующие зависимости, и они тут же становятся поверхностью атаки, как только кто-то регистрирует галлюцинированное имя, о чем писал мой коллега из InfoWorld Lucian Constantin.

Не стоит делать из этого вывод, что люди всегда выигрывают. В конце концов, разработчики давно уже превращали dependency graph в хаос, еще до того, как чатботы научились извиняться с чрезмерной вежливостью. Но разрешать агентам «помогать» добавлять и обновлять зависимости без ограничителей — значит очень быстро получить знакомую проблему.

Слой MCP — это та же ловушка, только в другой форме. Microsoft документировала tool poisoning, когда вредоносные инструкции прячутся в метаданных инструмента, по которым модель решает, что вызывать. В собственных red-team-исследованиях Microsoft обнаружила, что опора на модель в соблюдении safety-инструкций приводила к нарушениям политики более чем в 25% случаев и сделала вывод: одного instruction-following недостаточно, чтобы считать его границей безопасности. OWASP сказал еще прямее: ответ инструмента попадает прямо в контекст модели, без эквивалента проверки, которую описание инструмента проходит при подключении, а ограничение вроде «не читать файлы вне /tmp» обеспечивается доброй волей модели, а не access control.

Это плохо. А промпты еще хуже?

Sean Goedecke недавно утверждал, что промпты тоже создают технический долг и тихо деградируют. Промпт, который работал для одной модели, ведет себя иначе в следующей. Сложите их достаточно много — файлы AGENTS.md и CLAUDE.md, skills, rules, tool descriptions — и вы незаметно построите альтернативный control plane для того, как пишется ваш софт. Большинство команд его не тестируют, не ревьюят и не чистят, оставляя агентам возможность принимать худшие решения, звуча при этом вполне разумно.

«Последнее» — не то же самое, что безопасное

Экстремальная версия правил Hashimoto это не исправит, да и, откровенно говоря, большинству команд она не подойдет. У большинства компаний нет ни людей, ни терпения, ни дисциплины для такого подхода. Но если отбросить экстремальную часть, лежащая под ней логика совершенно верна: у каждой зависимости должна быть причина существовать, а у каждого обновления — причина попасть в релиз.

Это идет против современной разработки, где добавить пакет кажется дешевле, чем подумать. И еще сильнее идет против того, как работают агенты. Агенты отлично умеют находить библиотеку, импортировать ее и идти дальше. Они оптимизируют кратчайший путь до проходящего теста, а не долгосрочное здоровье dependency graph. Это та же дыра, к которой я постоянно возвращаюсь, когда говорю о evals: ИИ не отменяет инженерную дисциплину; он повышает цену ее игнорирования. Модель может сделать изменение быстрее. Но она не может надежно сказать, должно ли это изменение быть в вашей системе. Это по-прежнему ваше решение.

Скрытые баги не останутся скрытыми

Но у подхода Hashimoto есть проблема, даже в неэкстремальном варианте. Его ставка предполагает, что не обнаруженный дефект в зафиксированной зависимости так и останется не обнаруженным. Для большей части истории ПО это было безопасным предположением: найти глубокую логическую ошибку в зрелом коде было медленной, дорогой, человеческой работой. С ИИ это предположение больше не работает.

В апреле Claude Mythos Preview от Anthropic автономно нашел и собрал рабочие эксплойты для 16-летней ошибки в FFmpeg и 17-летней уязвимости, дающей root-доступ, в NFS-сервере FreeBSD, потратив менее $20 000 и около тысячи запусков. Месяцем позже исследователи Google по угрозам отметили первый AI-developed zero-day, замеченный в реальном мире, — семантическую логическую ошибку именно того типа, который традиционные сканеры пропускают.

Старые зависимости казались безопасными, но теперь хакер может недорого арендовать поиск слабых мест в броне.

Это не опровергает Hashimoto, но требует уточнения его правил. Урезать зависимость до конкретного use case — значит получить лучший контроль, потому что каждая функция, которую вы не импортировали, не может быть превращена в zero-day против вас. Forking позволяет патчить тогда, когда вам удобно, а не ждать upstream-сопровождающего. И важно, что те же модели, которые оценивают ваш код для атакующего, могут и должны сначала оценивать его для вас.

Правило никогда и не было «не обновляй». Оно другое: знать свою поверхность атаки, держать ее маленькой и постоянно ее оценивать, потому что теперь это делают все остальные.

Меньше вещей, но лучше понятых

Да, это меняет правила игры. Лучшие команды AI engineering не будут теми, кто подключит агентов ко всему подряд, как бы эффектно это ни звучало. Умные инженеры будут точно знать, что именно они подключили, зачем это нужно и что произойдет, если это изменится.

Это не значит запрещать MCP-серверы, agent tools или сторонние пакеты. Это было бы глупо. Это значит относиться ко всему этому как к production dependencies, потому что именно ими они и являются. Если MCP-сервер может читать почту, запрашивать клиентские данные или выполнять код, он заслуживает той же проверки, что и любая другая привилегированная интеграция. Если файл с промптами определяет, как агент правит вашу кодовую базу, он должен жить в version control, проходить review и удаляться, когда перестает быть полезным. Здесь сходятся совет Goedecke и инстинкт governance: Goedecke держал бы этот слой конфигурации настолько тонким, насколько возможно, исходя из логики, что самый дешевый долг — это промпт, который вы никогда не писали. Сторонники governance, напротив, версионировали бы, ревьюили и ограничивали все, что осталось.

Это на самом деле не ново. История индустрии полна технологий, которые казались освобождающими, пока не становились операционной обузой, и подход к ним обычно один и тот же. Microservices должны были освободить нас от монолита, пока многие команды не обнаружили, что поменяли одну большую проблему на 200 маленьких, связанных ненадежными сетями. Kubernetes должен был стандартизировать инфраструктуру, пока компании не поняли, что импортировали проект по распределенным системам в каждую команду.

Агенты идут по тому же пути — только быстрее. Они упрощают работу, добавляя слои делегирования. Эти слои становятся зависимостями, а зависимости становятся риском. Это не аргумент остановиться, но это аргумент быть внимательнее.


Материал — перевод статьи с английского.

Оригинал: AI’s brave new world of technical debt