Supply Chain AI

Цепочка поставки AI-системы шире зависимостей кода: в неё входят чужие модели, адаптеры, наборы данных, конвейеры конвертации и квантизации, а у агента — ещё MCP-серверы и реестры инструментов. Ключевое отличие от обычной: артефакт нельзя прочитать глазами, и статический анализ поведения не доказывает.

Суть

Обычная цепочка поставки — про уязвимости в коде и зависимостях. В AI к ней добавляются сущности, которые кодом не являются и потому обычными средствами не проверяются: веса моделей, LoRA-адаптеры, обучающие и оценочные наборы, результаты слияния и преобразования форматов. Ошибка на любом звене приходит в прод как поведение модели, а не как падение сборки.

Почему проверить артефакт трудно

Смена формата сериализации помогает, но не решает. Уход от Python-pickle, исполняющего произвольный код при загрузке, снимает самый грубый вектор. Но бэкдор может быть встроен прямо в вычислительный граф и пережить перенос в формат, который принято считать безопасным, — например ONNX. Отдельно существует риск разбора: специально собранный файл модели эксплуатирует ошибку памяти в парсере формата, как переполнение кучи в разборе GGUF у llama.cpp (CVE-2024-23496).

Отсюда практическое следствие: статический анализ не устанавливает безопасность поведения. Приёмка модели — это прогон поведенческого набора тестов перед переводом в любую непроизводственную среду, а не только сканирование файла.

Провенанс: карточка модели ничего не доказывает

Model Card описывает модель, но не подтверждает её происхождение. Скомпрометированный или похожий по названию аккаунт поставщика публикует вредоносную модель под доверенным именем, и по метаданным это не отличить.

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

Самая частая техническая причина — подвижная ссылка. Конвейер, разрешающий артефакт по тегу вроде latest, получает не то, что проверяли: между проверкой и использованием содержимое за тем же именем изменилось. Закрепление идёт по неизменяемому идентификатору содержимого, а не по имени версии.

Адаптеры и преобразования — отдельная поверхность

LoRA-адаптеры делают дообучение модульным, и ровно поэтому вредоносный адаптер компрометирует целостность базовой модели: и в средах совместного слияния, и на платформах инференса, которые скачивают адаптер и применяют его к уже развёрнутой модели.

Сервисы конвертации и слияния вносят изменения в момент преобразования, минуя ревью: проверяли одно, развернули результат преобразования.

Квантизация — не только оптимизация, но и точка атаки. Веса можно подобрать так, чтобы полноточная модель вела себя безобидно, а квантованный артефакт демонстрировал выбранное атакующим поведение (Egashira et al., 2025). Практическое следствие жёсткое: гарантии, полученные на полной точности, на развёрнутый квантованный артефакт не переносятся — проверять надо то, что поедет в прод (Quantization).

Slopsquatting — вектор, которого до ассистентов не было

Ассистенты-программисты массово выдумывают правдоподобные, но несуществующие имена пакетов. Атакующие регистрируют такие имена заранее, и предложенная ассистентом зависимость, поставленная без проверки, разрешается во вредоносный код.

Механика важна тем, что обходит привычную защиту: разработчик не ищет пакет сам и не сверяет его с экосистемой — имя пришло от инструмента, которому он доверяет. Проверка простая и дешёвая: существовал ли пакет до того, как его предложили, и кто его сопровождает.

Агентная половина: MCP-серверы и реестры инструментов

Для агента цепочка поставки продолжается в инструментах. Подключённый MCP-сервер — это чужой код с доступом к периметру, и относиться к нему надо как к зависимости, а не как к настройке (MCP, Tool Hijacking):

  • компоненты берутся только из доверенных источников и проверяются криптографически;
  • список разрешённых серверов — явный перечень, а не «что подключили, то и работает»;
  • локально запускаемый сервер идёт в песочницу с урезанным доступом к файловой системе, сети и системным вызовам (Agent Sandboxing).

Масштаб проблемы измерен: на 3 984 опубликованных навыках доля дефектов составила 36%, у 76 нашлась активная вредоносная нагрузка (Tool Hijacking).

Импортированная инструкция — тоже зависимость

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

Форма, которая это закрывает, повторяет обычный лок-файл:

  • на каждое импортированное умение — источник, путь внутри источника и хеш содержимого; изменился текст наверху — изменился хеш, и это видно;
  • установленное сверяется с локом после установки, а не только перед: иначе «поставилось» и «поставилось то самое» — разные утверждения, а выглядят одинаково;
  • место установки ровно одно. Одно и то же умение в проектном и в глобальном каталоге даёт две расходящиеся копии, и какая из них сработает, решает порядок разрешения имён, а не автор. Установщик обязан на это падать, а не выбирать;
  • глобальная установка помнит, каким локом она закреплена, и не переписывается молча из другого проекта с другим локом.

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

Вторая задача того же слоя — раскладка, и она ортогональна версии. Умения, описания субагентов и подключения MCP-серверов каждый агент принимает в своём формате и в своих каталогах. Проект, который не может диктовать участникам, каким агентом пользоваться, — открытый репозиторий, команда со свободой выбора, — упирается в это раньше, чем в дрейф версий.

Форма, которая это закрывает: обвязка описывается одним манифестом зависимостей — какие умения, какие серверы, какие субагенты, — а разворачивание под конкретного агента делает установщик, потому что знание о раскладке принадлежит ему, а не проекту. Участник говорит «поставь под мой агент» и продолжает работать привычным инструментом.

Полезно видеть, что две задачи разные: лок отвечает на вопрос «тот ли текст», манифест — на вопрос «куда его положить». Одно без другого не работает: закреплённое по хешу умение, разложенное не туда, просто не подхватится, и молча.

Патчинг зависимостей перестал быть фоновой задачей

Цепочка поставки ускорилась с обеих сторон одновременно, и обе половины усиливают друг друга.

Кода стало больше, а уязвимости растут вместе с ним. Связь объёма кода с числом дефектов безопасности известна и до агентов; порядок величины, который называют для тщательно проверяемого криптографического кода, — единицы уязвимостей на тысячу строк. Агентная разработка увеличивает поток кода, и вместе с ним — поток уязвимостей, причём в чужих зависимостях тоже, потому что их пишут так же.

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

Отсюда практический вывод, который стоит записать прямо: регулярный патчинг зависимостей из необязательной гигиены превратился в обязательную рутину, и делать его руками с той же частотой невозможно. Наблюдаемая автоматизация устроена так: ночной прогон читает ленту уязвимостей платформы, сверяет её с деревом зависимостей проекта, и там, где совпадение настоящее, сам открывает запрос на слияние с обновлением версии и описывает, чем проверял. Человек утром смотрит на готовое изменение и сливает.

Форма здесь важнее самого приёма: агент делает объёмную часть — сверку ленты с деревом и черновик изменения, — а решение остаётся за человеком, потому что цена ложного обновления версии на длинной ветке выше, чем цена его прочтения.

AI BOM: состав, который можно проверить машиной

Аналог SBOM для AI-артефакта: версионируемый машиночитаемый перечень наборов данных, весов, лицензий и заявлений о происхождении данных. Смысл появляется при двух условиях — перечень подписан до развёртывания, и сборка падает, если метаданные компонента отсутствуют. Неполный перечень, не влияющий на сборку, работает документацией, а не контролем.

Юридическая часть, которую забывают

Лицензии моделей и наборов данных предъявляют разные требования к использованию, распространению и коммерциализации. Отдельный риск — условия оператора модели: неясные правила обработки означают, что данные приложения могут попасть в обучение и всплыть позже, плюс возможные претензии по авторскому праву на материал, предоставленный поставщиком.

Связано с

  • Trusted Artifacts — признаки артефакта, которому разрешено ехать в прод
  • Tool Hijacking — инструменты и навыки как звено цепочки, с измеренной долей дефектов
  • Quantization — преобразование как точка атаки, а не только экономия памяти
  • MCP — чужой сервер в периметре агента
  • Agent Sandboxing — куда помещать локально запускаемый компонент
  • Abliteration — что можно сделать с моделью, получив к ней доступ
  • MLOps Pipeline — где в конвейере стоит граница продвижения