Перейти к содержимому
>_ITDITDПлатформа веб-безопасности

Руководства по безопасности

Код, написанный ИИ, привёл к утечке API-ключа и мошенническим списаниям — настоящей причиной была незакрытая уязвимость CVSS 10.0

У приложения, собранного с помощью ИИ, крадут API-ключ, и появляются мошеннические списания — частый сценарий инди-разработки. Но настоящая причина не код от ИИ, а незакрытая публичная RCE с CVSS 10.0. Разбираем механизм и профилактику.

Опубликовано 2026-06-07 6 мин чтения

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

Карточка инцидента — INCIDENT FILE
Класс
Утечка API-ключа / мошеннические списания
Серьёзность
Критическая (злоупотребление опубликованной CVSS 10.0)
Корневая причина
Pre-auth RCE в веб-фреймворке, месяцами оставшаяся незакрытой
Масштаб утечки
Все секреты окружения (вся связка ключей)
Масштаб выполнения
Осталось внутри непривилегированного контейнера (root хоста не пострадал)
Постоянное решение
①обновиться до исправленной версии ②сменить все ключи ③машинный мониторинг CVE
10.0
CVSS / худший класс
месяцы
как долго не закрывали
всё окружение
предполагаемый масштаб утечки
мониторинг
настоящая профилактика

«Остановили списания» ≠ «разобрались»

Остановить счёт — это первая помощь. Закрыть путь утечки — отдельная операция. Вы закончили только тогда, когда сделали и то, и другое.

Что произошло (хронология)

  1. День 0 — выкатили и запустили

    Приложение, собранное с помощью ИИ, было выпущено и работало в продакшене.
  2. Однажды — счёт взлетает

    Счёт за облачный ИИ внезапно подскакивает. Массовые задания на модели, которой никогда бы не пользовались, делающие чужую работу.
  3. Расследование — злоупотребление со стороны

    «Наше приложение сошло с ума» этого не объясняет. Кто-то посторонний запускал его с украденным ключом.
  4. Погоня — начинается настоящее расследование

    «Так откуда утёк ключ?» — вот это и было настоящим расследованием.

Почему сразу не поймали (ложные пути)

В том порядке, в котором совершались ошибки, — потому что именно ошибки и есть урок.

1

Поспешный вывод о виновнике

Первое предположение: «наш собственный резервный код пошёл вразнос». Но данные (что на самом деле обрабатывалось) ясно показали, что дело не в этом.
→ Прежде чем решить «моя вина» или «их вина», сначала посмотрите на данные.
2

Чистый grep чуть не принёс облегчение

Весь код, история git, связанные репозитории прочёсаны → нигде нет открытых ключей. Чуть не сдались с выводом «отследить невозможно». Уставившись в файлы, упустили утечку в среде выполнения.
3

Скрытие симптома показалось исправлением

Маскировка симптома на прокси чуть не сошла за «готово». Но маскировка оставляет RCE живой. Дыра остаётся открытой, пока не исправлен корень.

Чистый grep — это не отбой тревоги

Даже если ни в одном файле нет ключа, уязвимость может вытащить переменные окружения из работающего процесса. Утечки случаются в среде выполнения (RCE, HTTP-заголовки), а не только в файлах. См. Что такое RCE.

Настоящая причина: заброшенная опубликованная CVSS 10.0

Странная сигнатура в старых логах доступа мгновенно совпала с threat intel. У используемого диапазона версий веб-фреймворка была опубликованная pre-auth RCE (CVSS 10.0), которую уже эксплуатировали в дикой природе, — и она месяцами оставалась незакрытой.

  • Это была не пассивная ошибка — злоумышленник выполнял код на сервере и выкачивал окружение.
  • Спасло то, что выполнение осталось внутри непривилегированного контейнера (root хоста не захватили). Разбор взлома не нашёл устойчивого бэкдора, майнера или C2 — подтверждённым ущербом была кража секретов.
  • Поскольку внутренняя БД была достижима, в ответных мерах исходили из того, что содержимое БД тоже утекло.
Видимый симптом: внезапный неузнаваемый счёт (верхушка айсберга)
ватерлиния: всё, что видно
↑ украденные ключи позже перепродают / используют
выкачано всё окружение (каждый секрет)
↑ злоумышленник выполняет произвольный код на живом сервере
корневая причина: заброшенная опубликованная CVSS 10.0 (pre-auth RCE)
Внезапный счёт — лишь верхушка айсберга. Под водой настоящая причина: заброшенная опубликованная CVSS 10.0.

Урок: когда что-то ведёт себя странно, первым делом подозревайте известную CVE. Не считайте по умолчанию, что это ваш собственный баг.

Подсчёт тоже был неверным — судите по работающей версии

По ходу разбора сообщили о «ещё 8 уязвимых зависимостях» — тоже неверно. Их посчитали по нижней границе в package.json (диапазон с символом ^). По-настоящему опасными были лишь 2 зафиксированные (pinned) зависимости, оставшиеся позади.

Проверяйте свои реально работающие версии

Смотрите версии, которые на самом деле разрешились, — в lock-файле или в работающем контейнере.

# npm: посмотреть, что реально установлено
npm ls next react react-dom
 
# внутри работающего контейнера
docker exec <container> npm ls <package>

Истина здесь — эти числа, а не ^ в package.json.

Что сделали в первую очередь (воспроизводимые шаги)

1

Немедленно отозвать ключ, которым злоупотребляли

Первая помощь — лишь часть работы.
2

Обновить фреймворк до исправленной версии

Реально закрыть RCE. После обновления убедиться, что сигнатура утечки исчезла из логов.
3

Сменить каждый секрет

Считая утёкшими. По порядку «что можно использовать откуда угодно — в первую очередь»: ключи объектного хранилища → ключ подписи сессий → API-ключи → учётные данные БД.
4

Разбор взлома

Проверить на закрепление, посторонний cron, исходящий C2 (здесь ничего не было).
5

Защита на стороне аккаунта

Сменить пароль, включить MFA, проверить на незнакомые API-ключи.

Настоящая профилактика: пусть следят машины

Если свести к сути, этот инцидент был «человек не заметил опубликованную CVSS 10.0». Ручные обходы всегда что-то пропускают. Машины — нет.

Сканирование зависимостей, которое можно начать сегодня

Бесплатно для старта — один шаг в CI.

# OSV scanner (Google) проверяет ваш lock-файл
osv-scanner --lockfile=pnpm-lock.yaml
 
# На GitHub включите Dependabot (Settings репозитория → Security)

Этот сайт, согласно тому же уроку, сам мониторит свои зависимости на предмет CVE — мы практикуем то, что советуем.

Уроки

Частые ошибки

  • Считать делом сделанным на «остановили списания»
  • Расслабляться, потому что grep чистый
  • Маскировать симптом на прокси и чувствовать, что исправлено
  • Считать уязвимости по нижней границе package.json
  • Менять лишь один ключ, по которому подтверждено злоупотребление

Правильная защита

  • Считать первую помощь и «закрытие пути утечки» двумя разными задачами и делать обе
  • Подозревать и утечки в среде выполнения (RCE, заголовки)
  • Обновлять корень (фреймворк)
  • Судить по реально работающей версии
  • Заменять всё окружение, если оно утекло

В одну строку: взлетевший счёт был верхушкой айсберга. Настоящей причиной была заброшенная RCE с CVSS 10.0 — и истина пришла не от одной удачной догадки, а от того, что ошибались, сталкивались и стачивали ошибки.

Читать дальше

FAQ

QЕсли утёк API-ключ, достаточно ли отозвать только тот ключ, которым злоупотребляли?
A

Нет. Когда путь утечки лежит в среде выполнения (RCE или утечка через заголовки), исходите из того, что разом утекли все секреты окружения, и меняйте их все. Ключ, злоупотребление которым вы заметили, — лишь верхушка айсберга.

QЕсли grep по коду и по git не находит ключей, я в безопасности?
A

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

QЧто надёжнее всего предотвратит повторение?
A

Машинный мониторинг ваших зависимостей на предмет CVE. Корневой причиной здесь был человек, месяцами не замечавший опубликованную CVSS 10.0; Dependabot или osv-scanner структурно закрывают этот пробел.