Аудит безопасности LLM: один curl раскрыл все API-ключи | AiManual
AiManual Logo Ai / Manual.
29 Апр 2026 Гайд

Аудит безопасности LLM-платформы: как один curl раскрыл все API-ключи

Реальный кейс: как через SSRF и открытые API утекли ключи AI-платформы. Пошаговый гайд по аудиту и защите инфраструктуры LLM.

Утренний curl, который стоил ребятам работы

Представьте: вы запускаете curl -X GET https://your-llm-api.com/v1/keys и получаете обратно все API-ключи вашей платформы. Звучит как сценарий катастрофы? А это реальность, в которую попадают стартапы, копирующие конфиги из туториалов без оглядки на безопасность. В апреле 2026 года таких инцидентов становится только больше — взлом LiteLLM и утечка данных Mercor показали, что даже популярные прокси-решения могут быть дырявыми, если их неправильно развернуть.

Наша команда занимается red teaming AI-сервисов. И один из самых частых сценариев — даже не сложная инъекция промпта, а банальный HTTP-запрос к admin-ендпоинту. Без авторизации. Без проверки. Просто потому что разработчики забыли убрать отладку в продакшене. Или, что еще печальнее, считали, что «внутренняя сеть» — это надежная защита.

В этой статье — хроника реального аудита. Я покажу, как один curl может вытащить все ключи, и расскажу, как этого избежать.

Проблема: SSRF и открытые API в LLM-инфраструктуре

Большинство self-hosted LLM-платформ (LiteLLM, llama.cpp, LocalAI) используют REST API для управления ключами. По умолчанию эти эндпоинты слушают на localhost или на 0.0.0.0 без аутентификации. Команда docker-compose up -d — и сервис готов к работе. Но готов ли он к злоумышленникам?

💡 Суть уязвимости: LLM-прокси (например, LiteLLM) может иметь endpoint для создания/списка ключей. Если этот endpoint не защищен (нет заголовка Authorization или он не проверяется), любой, кто до него достучится, получит полный доступ.

Вот типичный сценарий. Вы разворачиваете LiteLLM как gateway к OpenAI, Anthropic, Mistral. Он слушает на порту 8000. Вы думаете: «У меня белый список IP, все ок». Но забываете, что внутри Kubernetes или Docker сеть может быть не изолирована. Или что ваш фронтенд также может делать запросы к внутренним сервисам (Server-Side Request Forgery). Или что кто-то забыл выключить дебаг-режим.

В результате — один запрос:

curl http://llm-gateway:8000/key/list -H "Authorization: Bearer "

Если токен не проверяется или пустой — привет, список всех API-ключей.

⚠️ Важный нюанс: В некоторых версиях LiteLLM (до 1.82.8) была критическая уязвимость, позволяющая обходить проверку мастер-ключа. Если вы до сих пор не обновились — сделайте это прямо сейчас.

Как это выглядит на практике: разбор атаки

Недавно мы проводили аудит для клиента, который использовал LiteLLM + собственную обвязку. Внутренний аудит показал, что эндпоинт /key/list отвечает на запросы без токена. Вот как выглядел процесс:

  1. Сканируем сеть: nmap -p 8000 10.0.0.0/24
  2. Находим открытый порт на контейнере lite-llm-1.
  3. Делаем curl: curl -s http://10.0.0.42:8000/key/list
  4. Получаем JSON с кучей ключей: openai, stripe, aws, и даже ключи от базы данных.

И это не теория. Аналогичная ситуация произошла с сервисом Moltbook, который взломали за 5 минут через Supabase. Там утекли 1.5M токенов и 35K email. Причина — открытый endpoint для аутентификации.

Разница только в том, что в случае LLM-платформы злоумышленник получает не просто доступ к чату, а возможность вызывать дорогие модели за ваш счет, читать промпты пользователей и подделывать ответы.

Пошаговый план аудита: проверьте свою платформу

Действуйте строго на своих тестовых окружениях. Если вы собираетесь тестировать продакшен — сначала получите письменное разрешение.

1Картографирование эндпоинтов

Соберите все endpoint'ы, которые слушает ваше LLM-приложение. Используйте netstat, lsof или просто посмотрите на docker-compose.yml. Типичные порты: 8000 (LiteLLM), 8080 (LocalAI), 8080 (llama.cpp server). Проверьте, слушает ли сервис на 0.0.0.0 (внешние запросы) или на 127.0.0.1 (только локально).

# Пример: проверить, какие порты открыты в контейнере
docker exec lite-llm-1 netstat -tulpn | grep LISTEN

2Тест на анонимный доступ

Для каждого эндпоинта сделайте запрос без заголовка Authorization или с пустым/фейковым токеном. Используйте этот список:

ЭндпоинтТипичное поведение при отсутствии авторизации
/key/listВозвращает список всех ключей (LiteLLM)
/v1/modelsПоказывает доступные модели, иногда с ключами в конфиге
/admin/keysAdmin-панель управления ключами
/metricsPrometheus метрики — можно увидеть эндпоинты

Если хотя бы один из них отвечает 200 OK — у вас проблема.

3Проверка SSRF

Если ваша LLM-платформа может отправлять запросы на основе пользовательского ввода (например, функция «использовать кастомную модель»), попробуйте заставить её обратиться к внутреннему сервису:

# Пример: подмена модели на http://internal-server/key/list
curl -X POST https://your-llm.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "http://localhost:8000/key/list", "messages": [{"role": "user", "content": "test"}]}'

Если в ответ придет не ошибка, а содержимое внутреннего эндпоинта — SSRF работает. Полное руководство по AI Red Teaming описывает аналогичную технику атаки на Grok от xAI.

4Анализ логов и конфигов

Посмотрите на файлы конфигурации. В них часто хардкодят ключи. Используйте grep -r "sk-" . в корневой директории проекта. Или сканируйте гитисторию. Как показал случай с атакой на цепочку поставок LiteLLM в PyPI, ключи могут быть вкомпилены в образ.

Нюансы и типичные ошибки

Теперь о том, что чаще всего идёт не так:

  • Сетевая изоляция — не панацея. Если ваш LLM-сервис стоит рядом с фронтендом, а фронтенд компрометируется (например, XSS), злоумышленник может сделать запрос от имени браузера и получить доступ к внутренним API. Решение — использовать отдельный API-ключ для каждого сервиса и никогда не доверять внутренней сети.
  • Debag-режим в продакшене. Многие разработчики забывают выключить LITELLM_DEV_MODE=true. В этом режиме авторизация отключена. Проверьте переменные окружения.
  • Отсутствие rate limiting. Даже если ключ защищен, атакующий может перебирать токены. Без лимита это вопрос времени. Практические методы защиты от prompt injection включают и rate-limiting.
  • Хранение ключей в ENV без секрет-менеджера. ENV-переменные доступны внутри контейнера каждому процессу. Если злоумышленник получит RCE (а критическая дыра в llama.cpp такое позволяет), он прочитает все ключи. Используйте Vault или AWS Secrets Manager.

💡 Лайфхак: Добавьте в CI/CD шаг, который прогоняет curl против каждого развернутого сервиса с пустым токеном. Если вернулось не 401 — сломайте билд.

Что делать, если вы нашли уязвимость

Ни в коем случае не паникуйте и не исправляйте на горячую — так можно положить весь сервис. Следуйте плану:

  1. Зафиксируйте доказательства. Сделайте скриншот или запишите curl-команду и ответ.
  2. Отключите внешний доступ. Если эндпоинт был открыт на всю сеть, временно заблокируйте его через сетевой ACL (iptables/security group).
  3. Смените все ключи. Немедленно выполните ротацию. Пример с инструкцией по ротации credentials — отличная база.
  4. Проверьте логи. Ищите подозрительные запросы к этому эндпоинту за последние дни. Возможно, утечка уже произошла.
  5. Сообщите команде и руководству. Без обвинений, с фокусом на исправлении.

И главное — не считайте, что «это не про нас». Когда ваш ИИ становится утечкой, исправлять всегда дороже, чем предупреждать.

Чек-лист для надежной защиты

  • ✔ Все административные эндпоинты закрыты за API-ключом с минимальными правами.
  • ✔ Сервис не слушает на 0.0.0.0 без необходимости.
  • ✔ Используется секрет-менеджер, а не ENV-переменные для ключей.
  • ✔ Включен rate-limiting и audit-логирование.
  • ✔ Регулярные сканирования на уязвимости (внедрите в CI/CD).
  • ✔ Команда обучена безопасным практикам развертывания.

Помните: самый опасный curl — тот, который вы не проверили. Завтра этот запрос может прийти не от вас, а от хакера. Не дайте ему шанса.

Подписаться на канал