
Представьте: вы выложили пет-проект на GitHub, через неделю получили письмо от хостинга о странной активности, а в логах — незнакомые запросы к базе. Причина банальная: ключ от этой базы месяцами лежал прямо в исходниках, а репозиторий был публичным. Такое случается не потому, что разработчик небрежный, а потому что «быстро запушить» почти всегда побеждает «правильно настроить секреты». Ниже — разбор того, где информация утекает чаще всего, и чек-лист, который реально пройти по своему проекту за один вечер.
Где чаще всего утекает информация
Прежде чем что-то настраивать, полезно понять типичные сценарии. Картина из чужих репозиториев и своих собственных косяков повторяется из раза в раз:
- API-ключи и токены прямо в коде, в самом простом виде: const apiKey = … в начале файла;
- файл .env случайно попал в коммит вместе с «полезными» изменениями;
- секреты печатаются в логах CI/CD — например, через echo или включённый set -x;
- ключ уехал во фронтенд-бандл: переменные с префиксами вроде NEXT_PUBLIC_ или REACT_APP_ попадают в клиентский JS и видны любому в DevTools;
- токен удалили из файла, но он остался в истории git и доступен каждому, кто сделает clone;
- секреты попали в промпт к ИИ-ассистенту вместе с куском кода;
- токен деплоя с правами администратора живёт годами и продублирован в трёх сервисах сразу.
Общее у всех пунктов одно: секрет легко скопировать, а заметить копирование почти невозможно. Поэтому основная стратегия — не «спрятать» данные, а сделать так, чтобы воровать было нечего: короткоживущие токены и минимум прав.

Правило первое: секретов нет в репозитории
Даже в приватном. Репозиторий — это файлы, которые копируются на десятки машин, попадают в бэкапы, форки и архивы подрядчиков. Считать приватность репозитория защитой — самая распространённая ошибка.
.env, .gitignore и файл-пример
Рабочая схема для небольших проектов: настоящие значения — в .env, сам файл — в .gitignore, а в репозитории лежит .env.example с пустыми или фиктивными значениями и комментариями. Тогда новый разработчик понимает, что нужно прописать, но ничего секретного не получает.
Отдельно проверьте, что .gitignore не «протекает»: шаблон вида *.env не поймает config.env.local в некоторых конфигурациях, а строка !.env.example может случайно вернуть файл обратно в индекс. После правок полезно запустить git status и глазами убедиться, что нужные файлы действительно игнорируются.
Когда проект растёт, .env перестаёт быть достаточным: файл всё ещё лежит на диске, в бэкапах и у каждого разработчика. Тогда логичный шаг — менеджер секретов. Для проектов в российских облаках это, например, Yandex Cloud Lockbox или сервисы VK Cloud; для зарубежных — HashiCorp Vault, AWS Secrets Manager, Doppler, Infisical. Смысл один: приложение получает секрет по API во время старта, а не хранит его в файле. На момент публикации бесплатные лимиты у всех этих сервисов разные, так что считайте под свой объём.
Если ключ уже попал в историю
Это важный пункт, который часто понимают неправильно. git rm убирает файл из последнего коммита, но не из истории: старый объект остаётся доступным по хешу. Переписать историю можно (git filter-repo, BFG Repo-Cleaner), но порядок действий такой:
- сначала отзовите и перевыпустите ключ — это действие номер один, потому что историю могли склонировать ещё до вашей чистки;
- затем чистите историю и просите коллег переклонировать репозиторий;
- потом включите автоматическую проверку на секреты, чтобы история не повторилась.
Чистка истории без ротации ключа — это уборка после того, как деньги уже вынесли. Классический идентификатор такой проблемы — CWE-798: Use of Hard-coded Credentials.
Секреты в CI/CD: где теряют бдительность чаще всего
Пайплайн — это код, который выполняется с вашими правами и обычно имеет доступ к продовой инфраструктуре. Именно поэтому секреты здесь нужны, но обращаться с ними нужно аккуратнее, чем в локальной среде.
Маскирование и логи сборки
В GitHub Actions секреты хранятся в настройках репозитория, в GitLab — в CI/CD Variables с включённой маской. Логи маскируются автоматически, но нюансы есть: если вывести секрет в base64, склеить с другой строкой или разбить по символам, маскирование не сработает. Проверка простая — запустите пайплайн на тестовой ветке и внимательно прочитайте лог. Если в нём видны значения переменных, считайте их скомпрометированными: логи доступны всем, у кого есть доступ к проекту в CI.
Минимальные права и короткоживущие токены
Самая дорогая привычка — выдать CI-токену права администратора «чтобы работало». Если сборке нужно только деплоить в один namespace, она не должна иметь доступ ко всему облаку.
- разделяйте окружения: staging и production — разные секреты и разные права;
- настраивайте ручное подтверждение (approval) для деплоя в прод, чтобы секреты прода не были доступны любому коммиту в основную ветку;
- используйте OIDC вместо статических ключей — например, подключение к облаку через OIDC в GitHub Actions. Тогда долгоживущего ключа в репозитории вообще нет;
- включите защиту основной ветки и обязательное ревью, прежде чем изменения попадут в пайплайн с секретами.
ИИ-ассистенты: новая привычка, новый риск
Отдельная тема, которая для многих ещё не стала привычкой. Когда вы копируете файл в чат с ChatGPT или Claude, вы отправляете его на чужой сервер. Если в файле был ключ — вы его отправили. То же самое касается автодополнения в редакторах: часть инструментов умеет читать открытые файлы проекта, включая конфиги.
Правила, которые я применяю сам:
- в промпт уходит минимальный фрагмент кода, а не файл целиком «на всякий случай»;
- секреты заменяются на плейсхолдеры (API_KEY=xxx) до копирования — если секретов нет в файле, их некуда утечь;
- перед работой с корпоративным кодом проверьте, обучается ли модель на ваших данных. У платных и корпоративных тарифов такие настройки обычно отключаемы, у бесплатных — часто включены; условия меняются, так что сверяйтесь с актуальной политикой сервиса на момент работы;
- если организация серьёзно относится к данным, разумный вариант — локальные модели или корпоративные развёртывания, где запросы не уходят наружу.
ИИ полезен и в обратную сторону — как быстрая проверка. Попросите ассистента просмотреть diff и найти признаки захардкоженных секретов, подозрительные зависимости и «временные» решения вроде отключённой проверки сертификата. Но относитесь к такому ревью как к подсказке: модель может пропустить очевидное или придумать несуществующую проблему. Автоматические сканеры в этом смысле надёжнее — о них ниже.
Зависимости и цепочка поставок
Утечка через собственный код — только половина истории. Вторая половина — пакеты, которые вы подключаете. Каждый npm-пакет или pip-модуль — это чужой код, который выполняется у вас и в CI, с вашими правами.
- фиксируйте версии через lock-файл и обновляйте осознанно, а не ради «свежести»;
- запускайте аудит зависимостей: npm audit, pip-audit, а для Docker-образов — сканер вроде Trivy;
- включите Dependabot или Renovate, чтобы узнавать об уязвимостях автоматически;
- проверяйте имена пакетов перед установкой — опечатки в названиях (typosquatting) это рабочий приём атакующих;
- отдельная новая угроза: ИИ-модели иногда предлагают несуществующий пакет, а злоумышленники заранее регистрируют такие имена. Если ассистент посоветовал библиотеку, которой вы не знаете, — посмотрите её историю и число загрузок, прежде чем ставить.
Что можно автоматизировать
Хорошая новость: базовую защиту почти целиком закрывают бесплатные инструменты, а настройка занимает пару часов.
- gitleaks или TruffleHog — поиск секретов в коде и истории коммитов;
- secret scanning — встроенная функция GitHub, включается в настройках репозитория (документация);
- pre-commit hook, который не даёт сделать коммит с ключом в файле: дешевле предотвратить, чем потом ротировать;
- SAST-анализ (Semgrep, CodeQL) — поиск типовых уязвимостей в собственном коде;
- двухфакторная аутентификация или passkey для аккаунтов в GitHub и облаке — банально, но именно через угнанный аккаунт секреты уводят чаще всего;
- регулярная ротация ключей по расписанию, а не только «когда что-то случилось».
Если хочется опереться на формализованный список требований, начните с OWASP Cheat Sheet по управлению секретами — там разложено по шагам, от хранения до отзыва.
Чек-лист: пройти по пунктам
- Прогнать историю репозитория сканером секретов (gitleaks или TruffleHog) и разобраться с находками.
- Убедиться, что .env и подобные файлы в .gitignore, а в репозитории лежит только .env.example.
- Отозвать и перевыпустить все ключи, которые когда-либо попадали в коммит.
- Перенести секреты прода в менеджер секретов или в переменные CI, а не в файлы на диске.
- Включить маскирование переменных в CI и вручную прочитать логи сборки на утечки.
- Выдать CI-токенам минимальные права; включить OIDC там, где это возможно.
- Настроить ручное подтверждение деплоя в прод и защиту основной ветки.
- Включить secret scanning и pre-commit hook, блокирующий коммиты с секретами.
- Включить двухфакторную аутентификацию на всех аккаунтах, связанных с проектом, и у подрядчиков.
- Настроить обновление зависимостей и сканирование уязвимостей (Dependabot, Trivy).
- Проверить настройки ИИ-ассистентов: не уходит ли код с секретами и обучаются ли модели на ваших данных.
- Записать план действий на случай утечки: какие ключи отзывать, где смотреть логи, кому сообщать.
Заключение
Абсолютной защиты не существует, и обещать её было бы нечестно. Но подавляющая часть реальных инцидентов — это базовые вещи: ключ в публичном репозитории, секрет в логе сборки, токен с правами администратора у всех подряд. Всё это закрывается за один рабочий вечер и почти без денег.
ИИ в этой теме работает в двух направлениях. Как источник риска — если бездумно копировать в чат конфиги вместе с ключами. И как помощник — если использовать его для быстрой проверки диффов и зависимостей, не доверяя ему финальное решение. Ротация ключей, минимальные права и автоматические сканеры дают больше спокойствия, чем любой «умный» ассистент. Начните с трёх пунктов чек-листа — самых неудобных, где ключ уже лежит в истории или у CI слишком много прав.