Секреты в коде: как ключи, токены и пароли попадают в репозиторий
Почему hardcoded credentials стали самым тихим и самым разрушительным классом уязвимостей — и что с этим делать до того, как сканер нашёл, а ротация так и не произошла
Почему это не вопрос "а вдруг кто-то заметит"
Утечки секретов из репозиториев обсуждают с начала 2010-х, но статистика продолжает расти. Причина не в незнании разработчиков — большинство прекрасно понимают, что API-ключ в коде это плохо. Причина в том, что давление velocity, фрагментированная ответственность за секреты и отсутствие автоматических барьеров формируют среду, в которой ошибки неизбежны.
Материал адресован CTO, VP Engineering, Tech Lead и AppSec-инженерам. Цель — дать системное понимание того, откуда берётся проблема, как выглядит типичный путь секрета от головы разработчика до публичного GitHub, и какие контролы на каком этапе работают.
Что такое "секрет" в контексте репозитория
Секрет — любые данные, предоставляющие доступ к системе или ресурсу: API-ключ, OAuth-токен, пароль базы данных, приватный SSH-ключ, сертификат, строка подключения, encryption key, JWT signing secret.
В терминах MITRE CWE-798 ("Use of Hard-coded Credentials") речь идёт о данных, жёстко встроенных в исходный код или конфигурационные файлы продукта. CWE-798 входит в CWE Top 25 наиболее опасных слабостей программного обеспечения. OWASP NHI Top 10 2025 ("Non-Human Identities Top 10") ставит Secret Leakage на позицию NHI2:2025 — второй по критичности класс после небезопасных учётных данных машинных аккаунтов.
Важно разделять два сценария:
- Секрет попал в код намеренно — "на время дебаггинга", "просто локально", "не успел вынести".
- Секрет попал в код незаметно — через CI/CD-логи, через AI-ассистента, через Dockerfile, через зависимость.
Оба сценария одинаково опасны. Но второй значительно хуже обнаруживается.
Масштаб проблемы в цифрах
Начиная с 2022 года ежегодные отчёты GitGuardian "State of Secrets Sprawl" формируют самую детальную публичную картину. Вот что говорят последние данные:
- В 2024 году на публичном GitHub было обнаружено 23,8 млн новых hardcoded-секретов — рост 25% год к году. GitHub в собственном отчёте считает иначе (учитывая и приватные репозитории, и форки) и называет цифру 39 млн, рост 67%.
- В 2025 году только на публичном GitHub зафиксировано 28,65 млн новых секретов — 34% прироста, крупнейший за всё время наблюдений.
- 64% секретов, подтверждённых как действительные в 2022 году, оставались активными и пригодными для эксплуатации по состоянию на январь 2026 года.
- 35% приватных репозиториев клиентов GitGuardian содержат plaintext-секреты. AWS IAM-ключи встречаются в приватных репозиториях в 5 раз чаще, чем в публичных. Hardcoded пароли — в 3 раза чаще.
- Самая быстрорастущая категория утёкших секретов — учётные данные AI-сервисов: +81% год к году в 2025-м. В 2025 году GitGuardian обнаружил 1 275 105 утёкших секретов, связанных с AI-сервисами. Только ключей DeepSeek в публичных репозиториях нашлось 113 000.
Все цифры выше относятся к обнаруженным утечкам. Реальные объёмы выше.
Пути попадания секретов в репозиторий
1. "Только для теста": hardcoded credential в исходном коде
Самый частый сценарий — разработчик вносит секрет напрямую в код в процессе отладки. Логика типичная: "потом уберу". Коммит летит в feature-ветку, открывается PR, ревьюер смотрит бизнес-логику, а не конфигурацию. Секрет уходит в main.
Ключевое свойство git, которое превращает это в постоянную проблему: даже если в следующем коммите строка удалена, она остаётся в истории навсегда. Команда git rm не удаляет данные — она только убирает файл из текущего дерева. Атакующие сканируют полную историю публичных репозиториев, а не только HEAD.
2. .env-файл без .gitignore
Стандартная практика хранить секреты в .env-файле для локальной разработки сама по себе разумна. Проблема возникает, когда .env не добавлен в .gitignore. Один git add . в спешке — и файл уходит вместе с остальным кодом.
Варианты этого паттерна распространены на все типы конфигурационных файлов: config.yml, application.properties, appsettings.json, terraform.tfvars, docker-compose.override.yml. Каждый из них может нести секреты, и каждый из них периодически коммитится случайно.
3. Инфраструктурные файлы и IaC
Terraform, Ansible, Helm-чарты, Kubernetes-манифесты — всё это код, и всё это регулярно попадает в репозиторий. Строка подключения к базе данных в values.yaml, IAM access key в Terraform-переменных, пароль в Ansible playbook — типичные кейсы. Особенность IaC: эти файлы часто ведут инженеры, далёкие от привычек разработчиков, у которых нет сформированной культуры работы с секретами.
4. CI/CD-конфигурации и логи
CI/CD-файлы (.github/workflows/*.yml, .gitlab-ci.yml, Jenkinsfile) часто хранятся прямо в репозитории. Если секрет прописан непосредственно в шаге pipeline, а не передаётся через переменную окружения CI-системы — он попадает в репозиторий.
Отдельный вектор — логи сборки. Если секрет передаётся через аргумент командной строки, а не через переменную окружения, он может оказаться в stdout pipeline. Платформы CI/CD маскируют только то, что явно объявлено как секрет. "Вторичные секреты" — данные, расшифрованные из зашифрованных файлов в процессе сборки, — зачастую в вывод попадают в открытом виде.
5. Docker-образы
Слои Docker-образа хранят все промежуточные состояния файловой системы. Если секрет скопирован в образ на одном слое, а удалён на следующем — в итоговом образе его "нет", но в истории слоёв он есть. Docker Hub содержит десятки тысяч образов с встроенными учётными данными. Один публично доступный образ с hardcoded AWS-ключом закрывает всю цепочку остальных мер.
6. AI-ассистенты: новый вектор
Это наиболее быстро растущий вектор утечек. Данные GitGuardian 2026: репозитории с активным GitHub Copilot содержат секреты в 6,4% случаев — на 40% выше среднего по платформе (4,6%). AI-ассистированные коммиты дают rate утечек 3,2% против базовых 1,5% для кода, написанного без AI-помощи.
Механизмы несколько:
- AI-инструменты, обученные на публичном коде, воспроизводят паттерны hardcoded credentials из обучающих данных.
- Разработчик показывает ассистенту контекст с секретом (например,
.env-файл) для генерации кода — и тот попадает в prompt history или в предложенный сниппет. - В 2024 году был задокументирован инцидент, когда Cursor отправлял содержимое
.env-файлов на серверы для tab completion, даже если они были добавлены в.cursorignore. - Исследователи из GitGuardian показали, что GitHub Copilot можно побудить воспроизвести реальные секреты из обучающих данных через специально сконструированные промпты.
Дополнительный аспект: MCP-конфиги (Model Context Protocol) стали новым слепым пятном. В 2025 году GitGuardian обнаружил 24 008 уникальных секретов в MCP-конфигурационных файлах на публичном GitHub; 8,8% из них были подтверждены как действительные в момент обнаружения.
7. Коллаборативные инструменты и смежные поверхности
Jira-тикеты содержат учётные данные в 6,1% случаев — обычно в виде логов ошибок, вставленных при описании бага. Confluence-страницы несут строки подключения, вставленные в документацию. Slack-каналы — временные ключи, отправленные "на секунду" коллеге. Ни один из этих каналов не сканируется по умолчанию.
Почему "приватный репозиторий" не защищает
Распространённое заблуждение: "у нас всё приватное, значит проблемы нет". Данные говорят об обратном. Приватные репозитории содержат секреты чаще публичных в абсолютных цифрах. Причины:
- Разработчики ослабляют бдительность, считая репозиторий "внутренним".
- Любой форк, клон на незащищённый ноутбук, экспорт архива или третья сторона с доступом создаёт копию истории.
- Случайное изменение visibility с private на public — документально подтверждённый вектор; GitHub фиксировал рост таких инцидентов в 2024 году.
- Компрометация одного developer-аккаунта (через фишинг, credential stuffing или утечку токена) даёт доступ ко всем приватным репозиториям этого пользователя.
Инцидент Sisense (2024) — классический пример: атакующие получили доступ к self-managed GitLab компании, нашли hardcoded AWS-токен, использовали его для доступа к S3-бакетам и выгрузили терабайты данных клиентов. CISA публично уведомляло об инциденте.
Реальные кейсы: когда "там ничего важного" оказывалось неправдой
Утечка кода New York Times (2024): злоумышленники получили доступ к GitHub-репозиториям через exposed token, скачали 270 GB исходного кода и внутренних данных. Инцидент попал в отчёт GitGuardian как иллюстрация того, что secrets sprawl является причиной резонансных взломов.
Атака Megalodon на GitHub (задокументирована исследователями): злоумышленники за несколько часов внедрили вредоносные коммиты в 5 561 репозиторий. Вредоносный код искал AWS и Google Cloud ключи, SSH-ключи, конфигурации Docker и Kubernetes, токены Vault, данные Terraform — по более чем 30 паттернам. Вектор входа — предположительно, скомпрометированный personal access token.
Взлом Treasury Department США (2024): был проведён через leaked API-ключ сервиса аутентификации BeyondTrust. Атакующие обошли многомиллионные инвестиции в безопасность, используя единственный открытый credential.
Git-история как вектор атаки
Это то, что большинство команд недооценивают. Git — append-only структура данных. Каждый коммит сохраняется в объектной базе репозитория и доступен через SHA. Команды git log, git show, git bisect, и специализированные инструменты типа git log -p --all позволяют просмотреть полную историю всех изменений.
Атакующие используют автоматизированные сканеры, которые:
- отслеживают новые публичные репозитории на GitHub в реальном времени;
- сканируют полную историю коммитов через GitHub API;
- используют GitHub Search API с запросами по конкретным расширениям файлов (
.env,.config,.ipynb) и ключевым словам (api_key,secret_key,access_token); - перехватывают "эфемерные коммиты" — данные, видимые в момент force-push, когда старые объекты ещё не удалены из reflog.
Исследования показывают, что активные секреты в публичных репозиториях могут быть скомпрометированы в течение нескольких минут после публикации.
Из этого следует практический вывод: единственный надёжный ответ на утечку секрета в репозиторий — немедленная ротация, независимо от того, публичный репозиторий или приватный, и независимо от того, была ли история "почищена".
Как правильно реагировать на обнаруженную утечку
Порядок действий имеет значение. Неправильная последовательность делает реакцию неэффективной.
Шаг 1: Немедленно ротировать секрет
Это первое действие, а не последнее. Пока секрет активен, он скомпрометирован. Не нужно ждать окончания расследования или завершения очистки истории.
Шаг 2: Проверить логи доступа
До того как закрывать инцидент — посмотреть, использовался ли секрет. AWS CloudTrail, GCP Audit Logs, Azure Monitor, логи платформы — всё это даёт ответ на вопрос "а успели ли воспользоваться".
Шаг 3: Очистить историю репозитория
Удаление файла в новом коммите не решает проблему — секрет остаётся в истории. Для перезаписи истории используются два инструмента:
git filter-repo— официально рекомендуемый Git-проектом инструмент, заменяет устаревшийgit filter-branch.- BFG Repo-Cleaner — более быстрый специализированный инструмент, удобен для замены строк по паттерну.
После перезаписи истории необходим force-push, а все участники команды должны заново клонировать репозиторий — их локальные копии содержат старую историю.
Важная оговорка: если репозиторий публичный, считайте секрет скомпрометированным навсегда независимо от очистки. Автоматические сканеры успевают сохранить данные до того, как история переписана.
Шаг 4: Разобрать причину
Без разбора причины инцидент повторится. Типичные вопросы: почему секрет оказался в коде, был ли .gitignore настроен, проходил ли PR ревью, работал ли pre-commit hook.
Инструментарий: что ставить и где
Pre-commit hooks (превентивный уровень)
Инструменты, запускаемые локально перед коммитом:
- gitleaks — сканирование по regex-паттернам и энтропии, поддержка кастомных правил, интеграция с GitHub Actions.
- trufflehog — detector-based подход, сотни встроенных паттернов для конкретных типов секретов (AWS, GitHub, Stripe, database connection strings), режим
--only-verifiedдля снижения false positives. - detect-secrets (Yelp) — акцент на минимизации false positives через baseline-файл.
- git-secrets (AWS) — простой hook-ориентированный инструмент с regex.
Pre-commit hooks дешевле всего по стоимости исправления: секрет поймали до того, как он вышел за пределы рабочей станции.
Сканирование в CI/CD (детективный уровень)
gitleaks и trufflehog могут быть встроены как шаги pipeline. GitHub Advanced Security включает встроенный secret scanning и push protection, который блокирует push при обнаружении известных паттернов. GitLab предоставляет аналогичный функционал в пакете Ultimate.
Важная деталь из отчёта GitGuardian: 58% всех обнаруженных секретов в 2024 году составляли "generic secrets" — пароли, строки подключения, кастомные токены без специфического формата. Автоматические сканеры хуже справляются с этим классом, поскольку не могут опираться на структурный паттерн.
Секретные менеджеры (системный уровень)
Правильный ответ на вопрос "где хранить секреты" — не в коде и не в файлах конфигурации, а в dedicated secret management системе:
- HashiCorp Vault — наиболее функциональный open-source вариант. Поддерживает dynamic secrets (генерация short-lived database credentials по запросу), fine-grained ACL, audit logs, множество authentication backend.
- AWS Secrets Manager — нативная интеграция с IAM, автоматическая ротация для RDS, Redshift и других AWS-сервисов.
- Azure Key Vault и GCP Secret Manager — аналоги для соответствующих облаков.
- Infisical — open-source альтернатива с поддержкой self-hosted.
OWASP Secrets Management Cheat Sheet сформулировал ключевой принцип: секреты должны быть эфемерными — иметь короткий lifetime, ротироваться автоматически и отзываться без необходимости деплоить код.
Для CI/CD специфически: используйте OIDC-аутентификацию вместо статических ключей. GitHub Actions и большинство облачных провайдеров поддерживают обмен временными токенами через OIDC — это полностью исключает необходимость хранить AWS_ACCESS_KEY_ID или аналоги как статические секреты репозитория.
Практический чек-лист: что проверять до merge и перед релизом
До merge (в PR-процессе)
- Нет ли в диффе строк с паттернами типа
key=,token=,password=,secret=,api_key=с непустым значением? - Добавлен ли
.envи все его вариации (.env.local,.env.production) в.gitignore? - Если в диффе есть новые конфигурационные файлы — проверены ли они на наличие секретов?
- Если в диффе есть изменения Dockerfile или docker-compose — нет ли в ARG/ENV значений, которые выглядят как секреты?
- Если в диффе есть CI/CD-конфиги — передаются ли секреты через переменные окружения CI-системы, а не hardcoded?
- Прошёл ли PR через автоматическое сканирование (gitleaks/trufflehog/встроенный сканер платформы)?
Перед релизом
- Ротированы ли все секреты, связанные с компонентами, затрагиваемыми в этом релизе?
- Нет ли в релизных артефактах (Docker-образах, бинарниках, конфигах) секретов, перенесённых из dev/staging в prod?
- Нет ли в логах CI-pipeline данных, которые не должны там быть?
- Соответствует ли scope прав у service account / IAM role принципу least privilege?
- Настроен ли alerting на аномальное использование ключей в production?
Системная гигиена (регулярно)
- Аудит активных секретов: какие существуют, где используются, когда последний раз ротировались.
- Проверка, что 100% секретов команды хранится в secret manager, а не в spreadsheet, Notion или Slack.
- Сканирование всей истории репозиториев (не только HEAD) — раз в квартал минимум.
- Проверка, что у AI-ассистентов (Copilot, Cursor и т.д.) нет доступа к
.env-файлам и конфигурационным файлам с реальными секретами.
Типичные ошибки и как их избежать
Ошибка 1: "Я удалил файл в следующем коммите"
Это не удаление. Секрет остаётся в git-объектной базе. Корректный ответ — перезапись истории через git filter-repo или BFG, force-push, ротация секрета.
Ошибка 2: "У нас приватный репозиторий, нам не страшно"
35% приватных репозиториев содержат секреты. Компрометация одного токена разработчика открывает доступ к всей истории.
Ошибка 3: "Сканер ничего не нашёл, значит секретов нет"
Generic secrets (пароли, кастомные строки подключения) составляют 58% всех утечек и хуже детектируются автоматическими инструментами. Отсутствие алерта от сканера не эквивалентно отсутствию секрета.
Ошибка 4: "Мы ротируем по расписанию раз в год"
64% секретов 2022 года активны в 2026-м. Rotation once a year leaves a 12-month attack window. Ротация должна быть автоматической и event-driven: при любом подозрении на компрометацию, при увольнении сотрудника с доступом, при изменении scope использования.
Ошибка 5: "AI написал код, он разберётся с безопасностью"
AI-ассистированные коммиты дают в 2 раза более высокий rate утечек секретов, чем код без AI-помощи. AI-инструменты — это инструменты скорости, а не безопасности. PR, написанный с Copilot, требует такого же (а в части конфигурации — более пристального) ревью, как и обычный.
Роль контроля изменений: почему мерж-гейт важен
Большинство команд сегодня работают быстрее, чем растёт их инструментарий контроля. PR дочитывается не до конца. Конфигурационные файлы в диффе смотрят хуже, чем логику. Новая зависимость приезжает незаметно. CI-лог никто не читает, если сборка прошла зелёной.
В этом контексте автоматический барьер на merge — не бюрократия, а компенсация системных ограничений внимания. Инструменты типа HighVibe работают как дополнительный слой контроля перед merge и релизом: анализируют конкретный diff (не весь репозиторий), включая конфигурационные файлы, IaC, CI/CD-конфиги и новые зависимости, и выдают короткий понятный сигнал — что в этом изменении заслуживает внимания и почему. Это не замена SAST/SCA и не альтернатива secret scanner'у, а ещё один контрольный слой именно в момент, когда изменение принимается в кодовую базу.
Ключевая логика: "сборка прошла" не означает "изменение безопасно". Рабочий PR с hardcoded ключом проходит юнит-тесты и линтер без замечаний.
Тренды: куда движется угроза
AI-сервисные учётные данные — самый быстрорастущий тип утёкших секретов. 81% прирост год к году в 2025-м, 1,27 млн обнаруженных экземпляров. С ростом числа команд, интегрирующих LLM-сервисы в продукты, количество Hugging Face токенов, OpenAI ключей, Anthropic API keys и аналогов в репозиториях продолжит расти.
MCP-конфиги как новая поверхность. С распространением агентных AI-инструментов конфигурационные файлы MCP-серверов становятся новым местом хранения учётных данных — и новым вектором утечки. Инструментарий для их сканирования пока отстаёт.
Рост "secrets in non-code artifacts": arXiv-препринты с LaTeX-исходниками, Docker Hub, Jupyter notebooks на Kaggle и Colab — всё это поверхности, которые традиционный secret scanning не покрывает.
Динамические секреты как архитектурный ответ. HashiCorp Vault, AWS Secrets Manager и аналоги движутся в сторону ephemeral credentials: секрет генерируется на момент запроса, имеет TTL в минуты или часы и автоматически аннулируется. При таком подходе утечка в репозиторий менее катастрофична — к моменту обнаружения секрет уже недействителен. Это не снимает необходимость не допускать утечек, но снижает window of exploitation.
Заключение: что делать прямо сейчас
Секреты в репозитории — не проблема отдельных разработчиков. Это системная проблема, растущая вместе со скоростью разработки, числом интеграций и распространением AI-инструментов. 28 миллионов новых утечек за один год на одной платформе — это не случайные ошибки, это структурный дефицит контроля.
Три немедленных действия, которые меняют картину:
- Включить push protection на уровне организации (GitHub/GitLab) — это блокирует известные паттерны секретов до того, как они попадают в репозиторий.
- Запустить сканирование полной git-истории всех репозиториев — не HEAD, а
--all. Результаты, скорее всего, будут неприятными. - Убедиться, что ни один секрет команды не живёт в spreadsheet, Notion, Slack или
.env-файле без записи в secret manager с настроенной ротацией.
Это фундамент. Дальше — зрелость: автоматическая ротация, ephemeral credentials, OIDC вместо static keys, обязательный security-gate на merge для конфигурационных изменений. Всё это существует и работает. Вопрос только в том, кто и когда это внедрит.
Источники
[1] GitGuardian — "State of Secrets Sprawl 2025" — https://blog.gitguardian.com/the-state-of-secrets-sprawl-2025/
[2] Passwork Blog — "The state of secrets sprawl in 2026: Key findings from GitGuardian's report" — https://passwork.pro/blog/the-state-of-secrets-sprawl-in-2026/
[3] GitHub Blog — "GitHub found 39M secret leaks in 2024. Here's what we're doing to help" — https://github.blog/security/application-security/next-evolution-github-advanced-security/
[4] GitHub Docs — "Secret leakage risks" — https://docs.github.com/en/code-security/concepts/secret-security/secret-leakage-risks
[5] Snyk — "Why 28 million credentials leaked on GitHub in 2025, and what to do about it" — https://snyk.io/articles/state-of-secrets/
[6] OWASP — "NHI2:2025 Secret Leakage — OWASP Non-Human Identities Top 10" — https://owasp.org/www-project-non-human-identities-top-10/2025/2-secret-leakage/
[7] OWASP — "Secrets Management Cheat Sheet" — https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
[8] MITRE CWE — "CWE-798: Use of Hard-coded Credentials" — https://cwe.mitre.org/data/definitions/798.html
[9] GitGuardian Blog — "Early Lessons from the Sisense Breach" — https://blog.gitguardian.com/sisense-breach/
[10] CSO Online — "AI programming copilots are worsening code security and leaking more secrets" — https://www.csoonline.com/article/3953927/ai-programming-copilots-are-worsening-code-security-and-leaking-more-secrets.html
[11] The Hacker News — "The New Frontier of Security Risk: AI-Generated Credentials" — https://thehackernews.com/expert-insights/2025/04/the-new-frontier-of-security-risk-ai.html
[12] GitGuardian Blog — "Yes, GitHub Copilot Can Leak Secrets" — https://blog.gitguardian.com/yes-github-copilot-can-leak-secrets/
[13] Cloud Security Alliance Labs — "Vibe Coding Security Crisis: Credential Sprawl and SDLC Debt" — https://labs.cloudsecurityalliance.org/research/csa-research-note-ai-generated-code-security-vibe-coding-202/
[14] AquilaX Blog — "OWASP Secrets Management & Environment Variables Best Practices" — https://aquilax.ai/blog/owasp-secrets-management-environment-variables
[15] GitGuardian Blog — "Secret Sprawl: Most common files to leak secrets" — https://blog.gitguardian.com/top-10-file-extensions/amp/
[16] OpenReplay Blog — "Scanning Your Repo for Secrets With TruffleHog" — https://blog.openreplay.com/scanning-repo-secrets-trufflehog/
[17] itsec.ru — "GitHub снова используют для атак на цепочку поставки ПО" — https://www.itsec.ru/news/github-snova-ispolzuyut-dlia-atak-na-zepochku-postavki-po
[18] anti-malware.ru — "7 ошибок в управлении секретами: как защитить ключи, токены и пароли" — https://www.anti-malware.ru/analytics/Technology_Analysis/7-Mistakes-in-Secrets-Management
[19] codeby.net — "Управление секретами в DevSecOps: лучшие практики и решения" — https://codeby.net/threads/upravleniye-sekretami-v-devsecops-ot-env-do-vault-i-otechestvennykh-reshenii.92282/
[20] cisoclub.ru — "Конвейер сборки без утечек: секреты в CI/CD и Docker" — https://cisoclub.ru/konvejer-sborki-bez-utechek-kritichnyh-dannyh-ili-zashhita-ot-uiljama-testera-v-cifrovuju-jepohu/