‑$200 за 40 минут: как я прошла принудительный экспресс‑курс по security для вайбкодинга

от автора

Я дизайнер и продакт, но как и многие из вас — последний год самостоятельно разрабатываю проекты с Claude Code. И, как многие, была уверена, что соблюдаю базовые правила безопасности.

Но два дня назад, меньше чем за час, злоумышленники потратили около $200, воспользовавшись моими API‑ключами Anthropic и OpenAI. И расследование этого инцидента превратилось для меня в очень быстрый и очень дорогой курс по безопасности AI‑разработки.

Этот текст в первую очередь для тех, кто, как и я, собирает продукты быстро, с ИИ‑ассистентом, и не является security‑инженером. Пусть эта статья станет вашим бесплатным экспресс‑курсом по безопасности.

Как все началось

Неспешно завтракая, ловлю пуш‑уведомление с почты:

Your organization has been disabled due to an outstanding balance.

Письмо о приостановке доступа к API Claude

Письмо о приостановке доступа к API Claude

За день до этого я пополнила баланс на $20. Перехожу в консоль Anthropic — и вижу баланс ‑$85. При этом Auto Reload у меня отключен, а Spend Limit стоит на $100 в месяц.

Первый раз при входе в Консоль баланс был -$85

Первый раз при входе в Консоль баланс был ‑$85

Первая мысль — где‑то зациклился мой код. Я тут же отзываю API‑ключ и вместе с Claude Code начинаю искать зависший процесс внутри приложения. Пока Клод проверяет сервер, я обновляю страницу консоли: минус уже больше $120. То есть одновременно произошло сразу несколько вещей — Anthropic остановил workspace, я отозвала ключ, а деньги продолжали списываться.

Минусовой баланс в Антропик

Минусовой баланс в Антропик

Тем временем Клод пишет, что кто‑то перебирает пароли от сервера, потом его подозрение падает на какой‑то зависший процесс. Он сканирует логи, отправленные ему отчеты из консоли и так далее.

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

Первые гипотезы Claude выдает уверенно и искать дальше не хочет

Первые гипотезы Claude выдает уверенно и искать дальше не хочет

Пока он гадал, я параллельно проверяла остальные аккаунты и балансы и чувствовала себя человеком с открытым кошельком, из которого на глазах исчезают деньги, — без понимания, почему и как это остановить. По OpenAI на балансе тоже обнаружился минус, но он, лапочка, ушёл в −$5 и все списания заморозил.

Почему деньги продолжали списываться после отзыва ключа и почему лимит расходов не спас

Я была уверена, что отключенное автопополнение плюс Spend Limit — это жесткое финансовое ограничение. На практике оказалось, что ни то, ни другое не останавливает уже запущенный запрос.

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

С лимитом расходов история похожая. Он не работает как аварийный рубильник: биллинг считает потраченное по завершенным запросам, а не по тем, что сейчас генерируются. Пока десять параллельных стримов дописываются, для системы этих денег еще не существует. К моменту, когда счетчик увидел превышение и Anthropic остановил workspace, все уже было потрачено — письмо о блокировке пришло мне вдогонку, а не заранее. Формально лимит сработал. Практически он зафиксировал ущерб, а не предотвратил его.

Что удалось выяснить

Мы с моим кофаундером, Claude Code, перебрали практически все стандартные сценарии компрометации. Установить удалось следующее: запросы шли напрямую к API, минуя мое приложение; использовалась модель, которую продукт вообще не вызывает; другие проекты на том же сервере не пострадали; ключи никогда не попадали в Git; признаков взлома самого сервера найти не удалось — правда, стоит честно сказать, что полноценных логов у нас не было, и смотрели мы то немногое, что было: auth.log, историю входов, активные соединения и access‑логи nginx.

Когда очевидные варианты закончились, он предложил выполнить обычную команду:

npm audit

Именно тогда выяснилось, что проект работал на Next.js 15.1.4 — версии, уязвимости в которой были публично известны с 2025 года. Claude Code поставил ее на мой проект в июне 2026 года, и, как оказалось, в проекты, которые я делала раньше — тоже.

Как Клод отвечает на вопрос об установке им старых версий

Как Клод отвечает на вопрос об установке им старых версий

Была ли виновата именно Next.js?

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

Почему? Потому что остальные наиболее вероятные сценарии удалось исключить. Если действительно использовалась известная RCE‑уязвимость, схема могла выглядеть примерно так:

Интернет     ▼HTTP-запроск (app.thebold.vc)     ▼nginx     ▼Next.js (уязвимая версия)     ▼RCE(выполнение произвольного кодав процессе Next.js)     │     ├── process.env.OPENAI_API_KEY     ├── process.env.ANTHROPIC_API_KEY     ├── process.env.JWT_SECRET     └── ...     ▼Отправить секретына сервер злоумышленника     ▼Злоумышленник использует API-ключи напрямую

Такая атака не оставляет привычных следов — ни SSH‑входов, ни компрометации root, ни чужих процессов. Код исполняется внутри легитимного процесса Next.js, читает переменные окружения и уходит.

Доказать это постфактум уже нечем: нужны были логи запросов, которых у нас с Клодом, конечно, не было.

‼️ Что вам стоит проверить прямо сейчас

1. Проверьте зависимости — и сделайте это частью процесса

Начните с разовой проверки: npm audit сравнивает установленные пакеты с базой известных уязвимостей GitHub Advisory Database. Дальше это должно стать регулярным: npm-check-updates показывает, что устарело, а правило «новые зависимости — только через @latest, и сразу npm audit после установки» имеет смысл прописать в CLAUDE.md или AGENTS.md — иначе AI‑ассистент снова поставит версию «по памяти».

Финальный уровень — не пускать уязвимости в прод. Проверку npm audit можно вшить в deploy.sh, чтобы сборка падала на критических находках, но надёжнее вынести её в отдельный CI‑пайплайн (например, GitHub Actions), который гоняется на каждый push и PR — независимо от того, деплоит кто‑то в этот момент или нет.

2. Запустите /security review

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

3. Проверьте репозиторий на засвеченные секреты

gitleaks читает всю историю git — код, конфиги, скрипты, .env, .json, .yaml, README, всё, что когда‑либо попадало в коммиты, — и ищет строки, похожие на ключи и токены. Ставится через brew install gitleaks. Один прогон покажет, что уже утекло, но правильнее повесить его на pre‑commit hook, чтобы ключ физически не мог попасть в коммит.

4. Не держите боевые секреты в локальном проекте

Claude Code не выгружает проект целиком — но все, что он прочитает, уходит в API. Включая .env, если он в него заглянет. Запретите это явно, добавив .env в deny‑правила чтения, и не храните production‑ключи локально: для боевого окружения их безопаснее заводить прямо на сервере или в secret manager.

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

5. Настройте Rate Limits в консоли

Это единственная настройка, которая реально ограничивает ущерб. Spend Limit не прерывает уже запущенные запросы, а Rate Limit просто не дает стартовать десяти стримам одновременно. Настройка доступна не во всех типах workspace, и про нее знают далеко не все — объяснить текстом сложно, поэтому я записала короткий скринкаст.

Rate Limits  в Claude Console

Rate Limits в Claude Console

6. Включите логи, пока ничего не случилось

Самое неприятное в этой истории — не деньги, а то, что я до сих пор не знаю наверняка, как утекли ключи. Логи запросов к API и access‑логи приложения стоят ноль, пока всё хорошо, и становятся единственным доказательством, когда всё плохо. Заведите их сегодня.

Что дальше

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

Очень милый сотрудник команды разработки из Anthropic

Очень милый сотрудник команды разработки из Anthropic

И последнее.

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

ссылка на оригинал статьи https://habr.com/ru/articles/1059488/