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

Останавливайте секреты до коммита с gitleaks: ловите утечки API-ключей до push

Закоммиченный API-ключ остаётся в истории Git. Как gitleaks ловит секреты через хук pre-commit и CI и почему после обнаружения ключ всё равно нужно отозвать.

Опубликовано 2026-06-12 Обновлено 2026-10-06 14 мин чтения
На этой странице

Для тех, кто использует Git в разработке в одиночку или малой командой и беспокоится «а вдруг я случайно закоммичу API-ключ?» Здесь нет механики атакующего — только механизм для остановки утечки секретов из вашего собственного репозитория.

Взгляд этого сайта: один .gitignore не защитит секреты

«Мой .env в .gitignore, так что всё нормально» — частая фраза, но она упускает ряд случаев. .gitignore лишь не даёт новым файлам отслеживаться; он не может поймать секреты, уже закоммиченные, принудительно добавленные впопыхах через git add -f или неожиданные имена вроде .env.local.bak. Он перекрывает лишь некоторые пути, которыми секрет попадает в репозиторий. Нужно что-то, что реально смотрит в содержимое коммитов и помечает «строки, похожие на секреты» — детектор. Для этого и нужен gitleaks.

Почему останавливать «до коммита»

Секреты опасны тем, что Git хранит историю вечно. Удалите из последнего файла — он остаётся в прошлых коммитах. А в момент push эта история копируется на другие машины, серверы и в логи CI.

остаётся в истории
нет в последнем, но есть в прошлых коммитах
push = распространение
скопировано на другие машины, серверы, в логи CI
нужен отзыв
раз утёкший ключ можно только перевыпустить
две проверки
остановить на pre-commit и CI

Так что защита секретов — это на самом деле профилактика до утечки, а не восстановление после неё. Та же идея, что и инвентаризация «не оставляйте секреты в публичной директории» (→ инвентаризация веб-корня), применённая к коду.

На каких этапах обнаруживать секреты

На пути секрета от кода к миру можно поставить две проверки: в момент локального коммита и прямо перед тем, как им поделятся (CI).

секрет в коде

API-ключ, ключ, токен

→

проверка 1: pre-commit

обнаружить и прервать локально при коммите

→

проверка 2: CI / cron

обнаружить после push, до merge/деплоя

→

публично / общий доступ

после этого считать утёкшим

Путь утечки и две проверки. Pre-commit останавливает локально; CI останавливает до merge/деплоя.

Как встроить gitleaks

1

Сначала просканируйте существующую историю

При внедрении один раз просканируйте всю историю репозитория командой gitleaks git (gitleaks detect в версиях до v8.19.0). Найти секреты, оставшиеся в прошлых коммитах, — первая задача. Всё найденное здесь, как ниже, считается требующим отзыва.
2

Добавьте проверку 1 хуком pre-commit

Запускайте gitleaks git --pre-commit --staged (ранее gitleaks protect --staged) на каждом коммите, чтобы прерывать на месте любой коммит, содержащий секрет. Добавьте его в фреймворк pre-commit (.pre-commit-config.yaml), чтобы та же проверка применялась у всех, локально.
3

Добавьте проверку 2 в CI / cron

Хуки каждый может отключить, так что проверяйте снова до того, как чем-либо поделятся. Запускайте gitleaks git как задание CI — или, для самостоятельных конфигураций, как периодический скан — чтобы ловить просочившееся (тот же подход машинного мониторинга, что и аудит зависимостей).
4

Настройте ложные срабатывания в .gitleaks.toml

Когда тестовые ключи-заглушки или примеры срабатывают, скорректируйте правила и allowlist в .gitleaks.toml. Правильная практика — не «подавить предупреждение», а «записать, почему это безопасно»: исключение без обоснования может стать причиной следующего инцидента.

При обнаружении «отзыв» идёт первым; переписывание истории — потом

Когда вы находите секрет, который был закоммичен и запушен, высший приоритет — отозвать и перевыпустить (сменить) этот ключ или токен. Стереть его из истории через git filter-repo важно, но это лишь уборка, чтобы «остановить дальнейшее распространение». Исходите из того, что секрет, достигший публичного репозитория, форка, лога CI или чужого клона, невосстановим — сначала аннулируйте его, затем чистите историю. Переверните порядок — и его используют, пока вы ещё удаляете.

Опора на .gitignore

  • лишь предотвращает новое отслеживание
  • секреты, уже закоммиченные, остаются незамеченными
  • бессилен против git add -f или странных имён файлов
  • не может проверить «я не собирался это добавлять»

gitleaks (обнаружение + практика отзыва)

  • реально инспектирует рабочее дерево и содержимое истории
  • останавливает двумя проверками: pre-commit и CI
  • при обнаружении — процедура, доходящая до отзыва
  • ложные срабатывания исключены с записанным обоснованием

Какую команду использовать (v8.19.0 и новее)

В v8.19.0 gitleaks перестроил свои команды. Старые detect и protect всё ещё запускаются, но объявлены устаревшими и больше не показываются в справке. Для новой настройки используйте эти:

КомандаЧто сканируетТипичное применение
gitleaks gitИсторию коммитов GitПервый скан всей истории, CI, сканы по расписанию
gitleaks git --pre-commit --stagedИзменения, которые вы собираетесь закоммитить (staged)Хук pre-commit (официальный хук запускает именно это)
gitleaks dirПапки и файлы, включая те, что не в GitПубличные веб-папки, резервные копии, распакованные zip-релизы
gitleaks stdinТекст, переданный через стандартный вводВывод или логи других команд

gitleaks завершается с кодом 1, если находит хотя бы одну утечку, и с кодом 0, если не находит ничего, поэтому задания CI и cron могут падать по этому коду. Добавьте --redact, чтобы сам секрет никогда не попадал в вывод или логи.

Пример настройки: хук pre-commit и GitHub Actions

С фреймворком pre-commit положите этот файл в корень репозитория. При добавлении укажите в rev последний релиз (v8.30.1 на октябрь 2026 года).

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks

Помимо gitleaks (сборка на Go), в id можно указать gitleaks-docker (запуск в Docker) или gitleaks-system (использует gitleaks, уже установленный на машине). Затем каждый выполняет это на своей машине:

pip install pre-commit        # install pre-commit itself
pre-commit install            # register the hook in this repo (once per clone)
pre-commit run --all-files    # check every file once, right after registering
pre-commit autoupdate         # run now and then to move rev to a newer release

Для CI на GitHub есть официальный GitHub Action. Ему нужна вся история, поэтому делайте checkout с fetch-depth: 0.

# .github/workflows/gitleaks.yml
name: gitleaks
on:
  pull_request:
  push:
  schedule:
    - cron: "0 4 * * *"
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v3
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}

Для репозиториев, принадлежащих аккаунту организации, Action нужен лицензионный ключ (GITLEAKS_LICENSE). В официальном README сказано, что ключ бесплатно выдаётся на gitleaks.io и для личных аккаунтов не нужен. На собственном Git-сервере или в CI, отличном от GitHub, то же самое делает запуск gitleaks git --redact внутри задания.

Где проверять: сравнение четырёх мест

Любая отдельная проверка оставляет пробел. Если разложить, что каждая останавливает и где пропускает, становится понятно, зачем их сочетать.

ГдеКогда останавливаетЧто покрываетПробелы и ограничения
Хук pre-commit (локально)До коммитаИзменения в stagedПропускается через git commit --no-verify или SKIP=gitleaks. Клонирование репозитория не устанавливает хук
CI (GitHub Actions и т. п.)До merge или деплояЗапушенные коммиты и историяPush уже произошёл. В публичном репозитории считайте секрет утёкшим
Скан по расписанию (cron)Находит позжеВся история репозиторияЗадержка до обнаружения. Ловит то, что новые правила находят в старых коммитах
Push protection GitHubПри push в GitHubТипы секретов, поддерживаемые GitHubМожно обойти, указав причину. Не работает на других Git-серверах

Push protection для пользователей GitHub по умолчанию включена для push в публичные репозитории. Это бесплатная страховка, но она не останавливает локальные коммиты, а ключи неподдерживаемых форматов или вручную собранные строки подключения могут пройти (подробнее — почему учётные данные, раскрытые на GitHub, всё ещё действуют). gitleaks покрывает шаг до этого и всё за пределами GitHub.

Как проверить свою конфигурацию

Однократная настройка не значит, что всё работает. В своём репозитории проверьте это по порядку.

1

Проверьте версию gitleaks

Выполните gitleaks version. В версиях старше v8.19.0 нет gitleaks git и других новых команд, поэтому обновитесь.

2

Проверьте, что хук зарегистрирован

Найдите .git/hooks/pre-commit. Если git config --get core.hooksPath указывает на другую папку, смотрите там. Git не копирует хуки при клонировании, поэтому на новой машине или в свежем клоне снова выполните pre-commit install.

3

Один раз просканируйте всю историю

Из корня репозитория выполните gitleaks git --redact -v. Без находок код завершения — 0. Если что-то найдено, по имени файла и коммиту в выводе проверьте в консоли выпустившего сервиса, действует ли ещё этот ключ.

4

Просканируйте и папки вне Git

Публичная папка на сервере, резервные копии и содержимое zip-архивов, которые вы выпускаете, не видны при скане истории Git. Проверьте их командой gitleaks dir (путь к папке) --redact (→ инвентаризация публичной директории).

5

Проверьте, коммитился ли когда-нибудь .env

Выполните git log --all --oneline -- .env, чтобы увидеть, затрагивал ли .env какой-либо прошлый коммит. Если появится хотя бы одна строка, содержимое с того момента есть в истории.

Обработка ложных срабатываний

Тестовые ключи-заглушки и примеры в документации часто помечаются. Есть три способа их исключить; используйте самый узкий из работающих.

  • Для строки: добавьте комментарий gitleaks:allow на этой строке
  • Для находки: добавьте отпечаток (fingerprint) из вывода в .gitleaksignore в корне репозитория (в README это помечено как экспериментальная функция)
  • Для файла или шаблона: добавьте его в allowlist в .gitleaks.toml

Если вы пишете собственный .gitleaks.toml, укажите useDefault = true в разделе [extend], чтобы сохранить правила по умолчанию. Конфигурация только с вашими правилами молча теряет ключи, которые поймали бы правила по умолчанию.

Если в старом репозитории много существующих находок, передайте прошлый отчёт в --baseline-path, чтобы сообщались только новые находки. Но сначала отзовите ключи из этого отчёта. Включение ключа в baseline не делает его безопасным.

Частые ошибки и как их исправить

  • Считать, что файла конфигурации достаточно: хук ничего не делает, пока кто-то не выполнит pre-commit install. Пусть это сделают все, а ту же проверку запускайте в CI как второй слой.
  • Привыкнуть к --no-verify: сделайте проверку в CI обязательным условием для merge, чтобы пропущенный хук всё равно был пойман.
  • Выводить секреты в логи CI: добавьте --redact. Логи CI тоже читают многие.
  • Сканировать в CI неглубокий клон: проверяется только последний коммит, а секреты в истории пропускаются. Задайте fetch-depth: 0.
  • Остановиться на удалении из истории: собственное руководство GitHub ставит первым шагом отзыв или смену секрета. Копии в форках, клонах и кэшах удалить нельзя.
  • Вносить настоящий ключ в allowlist как «ложное срабатывание»: пишите причину в комментарии и проверяйте её при ревью.

Реальный случай: ключ доступа, оставленный в открытом доступе

7 октября 2022 года Toyota Motor Corporation объявила, что часть исходного кода пользовательского сайта её сервиса подключённых автомобилей T-Connect была открыта на GitHub. Согласно объявлению компании:

  • В декабре 2017 года подрядчик, разрабатывавший сайт, по ошибке загрузил часть исходного кода в аккаунт GitHub с публичными настройками
  • В коде был ключ доступа к серверу данных, где хранилась информация о клиентах
  • Код был сделан приватным 15 сентября 2022 года, а ключ доступа сменён 17 сентября
  • Затронуто 296 019 адресов электронной почты и номеров управления клиентами. Журналы доступа не показали использования третьими лицами, но компания заявила, что не может полностью это исключить

Между загрузкой и удалением прошло около пяти лет. К тому же это произошло вне собственных репозиториев компании — в аккаунте подрядчика. Сканер на ваших репозиториях не достаёт до всех мест, куда попадает ваш код, поэтому также ограничивайте, что может каждый ключ, и меняйте ключи по графику. И даже здесь ключ сменили через два дня после того, как код убрали: нашли — замените ключ.

Приватный репозиторий тоже не безопасное место для секретов. В случае CAMPFIRE в 2026 году, по словам компании, отправной точкой стали злоупотреблённые учётные данные GitHub, а информация, видимая на GitHub, была использована для получения облачных учётных данных (→ взлом CAMPFIRE). Держите секреты вне и приватных репозиториев и сканируйте их gitleaks по расписанию.

Что делает сам этот сайт

Базовое правило этого сайта — полное недопущение секретов в Git — строки подключения и API-ключи живут только в защищённой конфигурации на сервере (env-файл с ограниченными правами), никогда в открытом виде в репозитории или в передаточных заметках (→ держать секреты вне git / самостоятельный Git против GitHub). Поверх этого мы наслаиваем детекторы в расчёте на то, что люди всегда оступятся. Проектирование гарантирует «не клади внутрь», а скан вроде gitleaks ловит «оно всё равно попало» — эти два слоя и есть защита этого сайта от утечки секретов. Принцип обращения с секретами тот же, что и в статьях .env-файлы и секреты и безопасное хранение паролей.

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

Источники

  • gitleaks (официальный репозиторий), README: команды (git, dir, stdin), устаревание detect/protect в v8.19.0, коды завершения, --redact, gitleaks:allow, .gitleaksignore, --baseline-path, расширение конфигурации — github.com/gitleaks/gitleaks / официальные определения хуков — .pre-commit-hooks.yaml / Releases
  • gitleaks-action (официальный GitHub Action), README: пример workflow и лицензионный ключ — github.com/gitleaks/gitleaks-action
  • Документация pre-commit (install, run --all-files, autoupdate, SKIP) — pre-commit.com
  • Документация Git, «githooks» (хук pre-commit и --no-verify) — git-scm.com
  • GitHub Docs, «About push protection» — docs.github.com / «Removing sensitive data from a repository» — docs.github.com
  • Toyota Motor Corporation, уведомление о возможной утечке адресов электронной почты клиентов (7 октября 2022 г., на японском) — global.toyota

FAQ

QЧто такое gitleaks?
A

Бесплатный инструмент, сканирующий рабочее дерево и историю коммитов Git-репозитория, чтобы обнаружить, не закоммичены ли секреты — API-ключи, приватные ключи, токены. Он находит «строки, похожие на секреты» по правилам regex и энтропии строк (случайности) и может работать как хук pre-commit или в CI для автоматических проверок.

QРазве помещение в .gitignore не защищает секреты?
A

Недостаточно. .gitignore лишь останавливает «новое отслеживание» — он не умеет обнаруживать секреты, уже закоммиченные, или принудительно добавленные через git add -f. Он предотвращает лишь часть случаев, так что сочетайте его с детектором вроде gitleaks и в pre-commit, и в CI.

QЧто если я случайно закоммитил и запушил секрет?
A

Считайте этот секрет утёкшим. Высший приоритет — не переписать историю, а отозвать и сменить (перевыпустить) раскрытый ключ или токен. Исходите из того, что секрет, попавший в публичный репозиторий или лог, нельзя отозвать — сначала аннулируйте его, затем чистите историю и добавьте профилактику (gitleaks).

QРаботают ли ещё gitleaks detect и gitleaks protect?
A

Они всё ещё запускаются, но объявлены устаревшими в v8.19.0 и скрыты из справки. Текущие команды — gitleaks git (сканирует историю коммитов), gitleaks dir (сканирует папки и файлы) и gitleaks stdin (сканирует ввод через конвейер). Проверка pre-commit теперь выполняется командой gitleaks git --pre-commit --staged — её же запускает официальный хук pre-commit. При настройке используйте новые команды.

QЕсли на GitHub включена push protection, нужен ли ещё gitleaks?
A

Они покрывают разное, поэтому используйте оба. Push protection для пользователей GitHub по умолчанию включена для push в публичные репозитории, но её можно обойти, выбрав причину, и она ничего не делает для локальных коммитов и для Git-серверов, отличных от GitHub. gitleaks останавливает секрет на вашей машине до коммита и применяет те же правила на собственном Git-сервере или в любом CI.

QКак сделать, чтобы gitleaks не срабатывал на тестовый ключ-заглушку?
A

Есть три способа: добавить комментарий gitleaks:allow на этой строке, внести отпечаток находки (fingerprint) в .gitleaksignore или исключить файлы или шаблоны через allowlist в .gitleaks.toml. Какой бы способ вы ни выбрали, оставьте комментарий, почему это безопасно. Больше всего стоит избегать внесения настоящего ключа в allowlist как ложного срабатывания.