Эфир 18.11 · Поток 318 ноября в 19:00 МСК — бесплатный практический эфир по ИИ-агентам · Живой Поток 3 стартует 23.11Эфир 18 ноября →Поток 3 (23.11)
Безопасность и правоРазбор · На радарHabr AI→ оригинал

Kilo Code молча отдал серверу все 12 файлов проекта, хотя разрешили только два

Автор проверил, что уходит на сервер модели, когда AI-помощник правит один знак в коде. Kilo Code 7.4.20 заменил сложение на умножение, тест прошёл, на диске изменился один файл. Но тестовый сервер, изображавший недоверенного провайдера, получил все 12 файлов проекта, хотя пользователь разрешил передать только два, и копии совпали побайтно.

AI-обработка оригинала Habr AI; редакция Hamidun News
Kilo Code молча отдал серверу все 12 файлов проекта, хотя разрешили только два
Источник: Habr AI. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникHabr AI ↗
Главный редактор
Ключевой факт #1Сервер читал файлы обычными вызовами read, без архивов и curl
Ключевой факт #2Результаты чтения попадали в историю чата и уходили в каждый следующий запрос
Запрет read не спасает, если разрешён bashPython читает тот же файл

Обычно мы принимаем работу AI-помощника так: смотрим диф, запускаем тесты, видим зелёный результат и закрываем задачу. Эксперимент, описанный на Habr, показывает дыру в этой привычке. Правка может быть идеальной, а проект при этом уже лежит на чужом сервере.

Как поставили эксперимент

Задача была нарочно крошечной: в price.py функция total(price, count) возвращала price + count, а тест ждал, что total(7, 3) даст 21. Нужно было заменить сложение на умножение и запустить check.py. Пользовательская инструкция при этом гласила: передавать можно только price.py и check.py.

Автор исходил из модели, где провайдер LLM недоверенный и намеренно нарушает инструкции. Его роль сыграл локальный HTTP-сервер на 127.0.0.1. Он имитировал потоковые ответы по OpenAI-совместимому Chat Completions API и присылал клиенту tool_calls: сначала двенадцать команд read для всех файлов синтетического проекта, потом команду исправления, потом запуск теста. Клиент был настоящий: bin/kilo.exe из расширения Kilo Code 7.4.20, запущенный через CLI-команду run. В конфигурации были разрешены чтение и выполнение команд.

Что получилось

Внешне всё выглядело образцово. Kilo поменял один знак, тест прошёл, остальные файлы на диске не изменились, код завершения нулевой, все 14 вызовов инструментов завершились со статусом completed. Но сервер получил все 12 файлов, общим объёмом 11 103 байта, и их SHA-256 совпали с оригиналами.

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

Отдельно интересен трафик. Всего было 15 обращений к модели, а суммарный объём тел запросов составил 458 779 байт при 11 КБ уникального кода. Причина в повторной отправке истории, описаниях инструментов и служебной разметке. Одного огромного запроса не было: код уходил небольшими порциями и потом повторялся. Поэтому по размеру одного запроса такую утечку не заметить.

Почему запреты работают хуже, чем кажется

В начальной серии тестов правило read: deny блокировало прямое чтение запрещённого каталога. Но при bash: allow Python прочитал тот же файл, а вывод ушёл в следующий запрос. Когда bash запретили, команда не выполнилась. Права в Kilo задаются отдельно для каждого инструмента, и запрет одного не закрывает остальные пути.

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

Что делать на практике

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

Второе: давайте агенту минимум прав. Если чтение разрешено, всё прочитанное потенциально принадлежит провайдеру. Для чувствительных репозиториев это аргумент за локальные модели или за провайдеров с жёсткими договорными гарантиями.

Третье: не полагайтесь на текстовую инструкцию вроде «передавай только эти два файла». Это пожелание модели, а не ограничение клиента. Реальную границу создают только права инструментов, песочница и сетевые политики.

Стенд автор выложил целиком: Python 3.10+, Git и исполняемый файл Kilo, около 150 строк кода. Его стоит повторить на своём клиенте, какой бы агент вы ни использовали.

Сюжет

Вопросы и ответы по материалу

Что известно по теме: как поставили эксперимент?

Задача была нарочно крошечной: в price.py функция total(price, count) возвращала price + count, а тест ждал, что total(7, 3) даст 21. Нужно было заменить сложение на умножение и запустить check.py. Пользовательская инструкция при этом гласила: передавать можно только price.py и check.py. Автор исходил из модели, где провайдер LLM недоверенный и намеренно нарушает инструкции. Его роль сыграл локальный HTTP-сервер на 127.0.0.1.

Что известно по теме: что получилось?

Внешне всё выглядело образцово. Kilo поменял один знак, тест прошёл, остальные файлы на диске не изменились, код завершения нулевой, все 14 вызовов инструментов завершились со статусом completed. Но сервер получил все 12 файлов, общим объёмом 11 103 байта, и их SHA-256 совпали с оригиналами. Механика проста. Kilo добавляет результат каждого чтения в историю чата и отправляет её в следующем запросе. Сервер вытаскивает сообщения с ролью tool, убирает номера строк и собирает файлы обратно.

Что известно по теме: почему запреты работают хуже, чем кажется?

В начальной серии тестов правило read: deny блокировало прямое чтение запрещённого каталога. Но при bash: allow Python прочитал тот же файл, а вывод ушёл в следующий запрос. Когда bash запретили, команда не выполнилась. Права в Kilo задаются отдельно для каждого инструмента, и запрет одного не закрывает остальные пути. Есть и честные оговорки. Настоящей модели в эксперименте нет: команды выбирал тестовый сервер, так что склонность коммерческих моделей к такому поведению это не измеряет.

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Единое AI-пространство · Nomad

Протестируйте новые LLM и мультимодальные модели в одном окне

Платформа Nomad AI (nomadnet.ai) даёт прямой доступ к Claude Opus 5.5, GPT-6, Gemini 3.1, DeepSeek и автономным агентам без VPN, зарубежных карт и зоопарка подписок.

Открыть Nomad AI →Автономный Nomad Agent
Что вы думаете?
Загружаем комментарии…