Сканирует git-репозитории (включая всю историю коммитов) на предмет утёкших секретов: API-ключей, паролей, токенов, приватных ключей. Незаменим при разведке — забытый секрет в старом коммите открытого репозитория часто оказывается самым быстрым путём внутрь инфраструктуры.
# Debian/Ubuntu, macOS (Homebrew) или бинарник с GitHub Releases: brew install gitleaks gitleaks detect --source . -v gitleaks detect --source . --report-format json --report-path report.json
┌─○───┐
│ │╲ │
│ │ ○ │
│ ○ ░ │
└─░───┘
[!WARNING] Gitleaks завершён по функционалу. Я не принимаю новые функции в Gitleaks. Будущие релизы будут содержать только исправления безопасности. Я переключаю своё внимание на Betterleaks
Gitleaks — это инструмент для обнаружения секретов, таких как пароли, ключи API и токены, в git-репозиториях, файлах и всего остального, что вы захотите передать ему через stdin. Если вы хотите узнать больше о том, как работает движок обнаружения, ознакомьтесь с этим блогом: Regex is (almost) all you need.
➜ ~/code(master) gitleaks git -v
○
│╲
│ ○
○ ░
░ gitleaks
Finding: "export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef",
Secret: cafebabe:deadbeef
RuleID: sidekiq-secret
Entropy: 2.609850
File: cmd/generate/config/rules/sidekiq.go
Line: 23
Commit: cd5226711335c68be1e720b318b7bc3135a30eb2
Author: John
Email: john@users.noreply.github.com
Date: 2022-08-03T12:31:40Z
Fingerprint: cd5226711335c68be1e720b318b7bc3135a30eb2:cmd/generate/config/rules/sidekiq.go:sidekiq-secret:23
Gitleaks можно установить с помощью Homebrew, Docker или Go. Gitleaks также доступен в виде бинарного файла для многих популярных платформ и типов ОС на странице релизов. Кроме того, Gitleaks можно использовать как хук pre-commit непосредственно в вашем репозитории или как GitHub Action с помощью Gitleaks-Action.
# MacOS
brew install gitleaks
# Docker (DockerHub)
docker pull zricethezav/gitleaks:latest
docker run -v ${path_to_host_folder_to_scan}:/path zricethezav/gitleaks:latest [COMMAND] [OPTIONS] [SOURCE_PATH]
# Docker (ghcr.io)
docker pull ghcr.io/gitleaks/gitleaks:latest
docker run -v ${path_to_host_folder_to_scan}:/path ghcr.io/gitleaks/gitleaks:latest [COMMAND] [OPTIONS] [SOURCE_PATH]
# From Source (make sure `go` is installed)
git clone https://github.com/gitleaks/gitleaks.git
cd gitleaks
make build
.pre-commit-config.yaml в корне вашего репозитория со следующим содержимым:repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.2
hooks:
- id: gitleaks
для нативного запуска gitleaks или используйте gitleaks-docker pre-commit ID для запуска gitleaks с помощью официальных Docker-образов
pre-commit autoupdatepre-commit install➜ git commit -m "this commit contains a secret"
Detect hardcoded secrets.................................................Failed
Примечание: чтобы отключить pre-commit hook gitleaks, вы можете добавить SKIP=gitleaks перед командой коммита,
и gitleaks будет пропущен
➜ SKIP=gitleaks git commit -m "skip gitleaks check"
Detect hardcoded secrets................................................Skipped
Gitleaks scans code, past or present, for secrets
Usage:
gitleaks [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
dir scan directories or files for secrets
git scan git repositories for secrets
help Help about any command
stdin detect secrets from stdin
version display gitleaks version
Flags:
-b, --baseline-path string path to baseline with issues that can be ignored
-c, --config string config file path
order of precedence:
1. --config/-c
2. env var GITLEAKS_CONFIG
3. env var GITLEAKS_CONFIG_TOML with the file content
4. (target path)/.gitleaks.toml
If none of the four options are used, then gitleaks will use the default config
--diagnostics string enable diagnostics (http OR comma-separated list: cpu,mem,trace). cpu=CPU prof, mem=memory prof, trace=exec tracing, http=serve via net/http/pprof
--diagnostics-dir string directory to store diagnostics output files when not using http mode (defaults to current directory)
--enable-rule strings only enable specific rules by id
--exit-code int exit code when leaks have been encountered (default 1)
-i, --gitleaks-ignore-path string path to .gitleaksignore file or folder containing one (default ".")
-h, --help help for gitleaks
--ignore-gitleaks-allow ignore gitleaks:allow comments
-l, --log-level string log level (trace, debug, info, warn, error, fatal) (default "info")
--max-archive-depth int allow scanning into nested archives up to this depth (default "0", no archive traversal is done)
--max-decode-depth int allow recursive decoding up to this depth (default "0", no decoding is done)
--max-target-megabytes int files larger than this will be skipped
--no-banner suppress banner
--no-color turn off color for verbose output
--redact uint[=100] redact secrets from logs and stdout. To redact only parts of the secret just apply a percent value from 0..100. For example --redact=20 (default 100%)
-f, --report-format string output format (json, csv, junit, sarif, template)
-r, --report-path string report file
--report-template string template file used to generate the report (implies --report-format=template)
--timeout int set a timeout for gitleaks commands in seconds (default "0", no timeout is set)
-v, --verbose show verbose output from scan
--version version for gitleaks
Use "gitleaks [command] --help" for more information about a command.
⚠️ В версии v8.19.0 было внесено изменение, в результате которого команды detect и protect были признаны устаревшими. Эти команды по-прежнему доступны, но скрыты в меню --help. Ознакомьтесь с этим gist для удобного перевода команд.
Если вы обнаружите, что v8.19.0 сломала существующую команду (detect/protect), пожалуйста, создайте issue.
Существует три режима сканирования: git, dir и stdin.
Команда git позволяет сканировать локальные git-репозитории. Под капотом gitleaks использует команду git log -p для сканирования патчей.
Вы можете настроить поведение git log -p с помощью опции log-opts.
Например, если вы хотите запустить gitleaks на диапазоне коммитов, вы можете использовать следующую
команду: gitleaks git -v --log-opts="--all commitA..commitB" path_to_repo. Дополнительную информацию смотрите в документации по git log.
Если в качестве позиционного аргумента не указан целевой объект, gitleaks попытается сканировать текущий рабочий каталог как git-репозиторий.
Команда dir (псевдонимы включают files, directory) позволяет сканировать каталоги и файлы. Пример: gitleaks dir -v path_to_directory_or_file.
Если в качестве позиционного аргумента не указан целевой объект, gitleaks будет сканировать текущий рабочий каталог.
Вы также можете передавать данные в gitleaks через команду stdin. Пример: cat some_file | gitleaks -v stdin
При сканировании больших репозиториев или репозиториев с длинной историей удобно использовать базовую линию (baseline). При использовании базовой линии
gitleaks будет игнорировать все ранее обнаруженные результаты, присутствующие в базовой линии. Базовая линия может быть любым отчётом gitleaks. Чтобы создать отчёт gitleaks, запустите gitleaks с параметром --report-path.
gitleaks git --report-path gitleaks-report.json # This will save the report in a file called gitleaks-report.json
После создания базовой линии её можно применить при повторном запуске команды detect:
gitleaks git --baseline-path gitleaks-report.json --report-path findings.json
После запуска команды detect с параметром --baseline-path отчёт (findings.json) будет содержать только новые проблемы.
Вы можете запускать Gitleaks как pre-commit hook, скопировав пример скрипта pre-commit.py в
каталог .git/hooks/ вашего репозитория.
Приоритет загрузки следующий:
--config/-c:
bash
gitleaks git --config /home/dev/customgitleaks.toml .GITLEAKS_CONFIG с путём к файлу:
bash
export GITLEAKS_CONFIG="/home/dev/customgitleaks.toml"
gitleaks git .GITLEAKS_CONFIG_TOML с содержимым файла:
bash
export GITLEAKS_CONFIG_TOML=`cat customgitleaks.toml`
gitleaks git ..gitleaks.toml в целевом пути:
bash
gitleaks git .Если ни один из четырёх вариантов не используется, gitleaks будет использовать конфигурацию по умолчанию.
Gitleaks предлагает формат конфигурации, которого вы можете придерживаться для написания собственных правил обнаружения секретов:
# Title for the gitleaks configuration file.
title = "Custom Gitleaks configuration"
# You have basically two options for your custom configuration:
#
# 1. define your own configuration, default rules do not apply
#
# use e.g., the default configuration as starting point:
# https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml
#
# 2. extend a configuration, the rules are overwritten or extended
#
# When you extend a configuration the extended rules take precedence over the
# default rules. I.e., if there are duplicate rules in both the extended
# configuration and the default configuration the extended rules or
# attributes of them will override the default rules.
# Another thing to know with extending configurations is you can chain
# together multiple configuration files to a depth of 2. Allowlist arrays are
# appended and can contain duplicates.
# useDefault and path can NOT be used at the same time. Choose one.
[extend]
# useDefault will extend the default gitleaks config built in to the binary
# the latest version is located at:
# https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml
useDefault = true
# or you can provide a path to a configuration to extend from.
# The path is relative to where gitleaks was invoked,
# not the location of the base config.
# path = "common_config.toml"
# If there are any rules you don't want to inherit, they can be specified here.
disabledRules = [ "generic-api-key"]
# An array of tables that contain information that define instructions
# on how to detect secrets
[[rules]]
# Unique identifier for this rule
id = "awesome-rule-1"
# Short human-readable description of the rule.
description = "awesome rule 1"
# Golang regular expression used to detect secrets. Note Golang's regex engine
# does not support lookaheads.
regex = '''one-go-style-regex-for-this-rule'''
# Int used to extract secret from regex match and used as the group that will have
# its entropy checked if `entropy` is set.
secretGroup = 3
# Float representing the minimum shannon entropy a regex group must have to be considered a secret.
entropy = 3.5
# Golang regular expression used to match paths. This can be used as a standalone rule or it can be used
# in conjunction with a valid `regex` entry.
path = '''a-file-path-regex'''
# Keywords are used for pre-regex check filtering. Rules that contain
# keywords will perform a quick string compare check to make sure the
# keyword(s) are in the content being scanned. Ideally these values should
# either be part of the identiifer or unique strings specific to the rule's regex
# (introduced in v8.6.0)
keywords = [
"auth",
"password",
"token",
]
# Array of strings used for metadata and reporting purposes.
tags = ["tag","another tag"]
# ⚠️ In v8.21.0 `[rules.allowlist]` was replaced with `[[rules.allowlists]]`.
# This change was backwards-compatible: instances of `[rules.allowlist]` still work.
#
# You can define multiple allowlists for a rule to reduce false positives.
# A finding will be ignored if _ANY_ `[[rules.allowlists]]` matches.
[[rules.allowlists]]
description = "ignore commit A"
# When multiple criteria are defined the default condition is "OR".
# e.g., this can match on |commits| OR |paths| OR |stopwords|.
condition = "OR"
commits = [ "commit-A", "commit-B"]
paths = [
'''go\.mod''',
'''go\.sum'''
]
# note: stopwords targets the extracted secret, not the entire regex match
# like 'regexes' does. (stopwords introduced in 8.8.0)
stopwords = [
'''client''',
'''endpoint''',
]
[[rules.allowlists]]
# The "AND" condition can be used to make sure all criteria match.
# e.g., this matches if |regexes| AND |paths| are satisfied.
condition = "AND"
# note: |regexes| defaults to check the _Secret_ in the finding.
# Acceptable values for |regexTarget| are "secret" (default), "match", and "line".
regexTarget = "match"
regexes = [ '''(?i)parseur[il]''' ]
paths = [ '''package-lock\.json''' ]
# You can extend a particular rule from the default config. e.g., gitlab-pat
# if you have defined a custom token prefix on your GitLab instance
[[rules]]
id = "gitlab-pat"
# all the other attributes from the default rule are inherited
[[rules.allowlists]]
regexTarget = "line"
regexes = [ '''MY-glpat-''' ]
# ⚠️ In v8.25.0 `[allowlist]` was replaced with `[[allowlists]]`.
#
# Global allowlists have a higher order of precedence than rule-specific allowlists.
# If a commit listed in the `commits` field below is encountered then that commit will be skipped and no
# secrets will be detected for said commit. The same logic applies for regexes and paths.
[[allowlists]]
description = "global allow list"
commits = [ "commit-A", "commit-B", "commit-C"]
paths = [
'''gitleaks\.toml''',
'''(.*?)(jpg|gif|doc)'''
]
# note: (global) regexTarget defaults to check the _Secret_ in the finding.
# Acceptable values for regexTarget are "match" and "line"
regexTarget = "match"
regexes = [
'''219-09-9999''',
'''078-05-1120''',
'''(9[0-9]{2}|666)-\d{2}-\d{4}''',
]
# note: stopwords targets the extracted secret, not the entire regex match
# like 'regexes' does. (stopwords introduced in 8.8.0)
stopwords = [
'''client''',
'''endpoint''',
]
# ⚠️ In v8.25.0, `[[allowlists]]` have a new field called |targetRules|.
#
# Common allowlists can be defined once and assigned to multiple rules using |targetRules|.
# This will only run on the specified rules, not globally.
[[allowlists]]
targetRules = ["awesome-rule-1", "awesome-rule-2"]
description = "Our test assets trigger false-positives in a couple rules."
paths = ['''tests/expected/._\.json$''']
Обратитесь к конфигурации gitleaks по умолчанию для примеров или ознакомьтесь с руководством по участию в проекте, если вы хотите внести вклад в конфигурацию по умолчанию. Кроме того, вы можете ознакомиться с этим блогом gitleaks, который охватывает расширенные настройки конфигурации.
required)В версии v8.28.0 Gitleaks представил составные правила (composite rules), которые состоят из одного «основного» правила и одного или нескольких вспомогательных или правил с required. Чтобы создать составное правило, добавьте таблицу [[rules.required]] к основному правилу, указав id и, при необходимости, ограничения близости withinLines и/или withinColumns. Фрагмент — это блок контента, который Gitleaks обрабатывает за один раз (обычно файл, часть файла или git diff), а сопоставление по близости указывает основному правилу сообщать о находке только в том случае, если вспомогательные правила required также находят совпадения в указанной области фрагмента.
Сопоставление по близости: Использование полей withinLines и withinColumns указывает основному правилу сообщать о находке только в том случае, если вспомогательные правила required также находят совпадения в указанном радиусе близости. Вы можете настроить:
withinLines: N — находки по правилу required должны находиться в пределах N строк (вертикально)withinColumns: N — находки по правилу required должны находиться в пределах N символов (горизонтально)Ниже приведены диаграммы, иллюстрирующие каждое поведение по близости:
p = primary captured secret
a = auxiliary (required) captured secret
fragment = section of data gitleaks is looking at
*Fragment-level proximity*
Any required finding in the fragment
┌────────┐
┌──────┤fragment├─────┐
│ └──────┬─┤ │ ┌───────┐
│ │a│◀────┼─│✓ MATCH│
│ ┌─┐└─┘ │ └───────┘
│┌─┐ │p│ │
││a│ ┌─┐└─┘ │ ┌───────┐
│└─┘ │a│◀──────────┼─│✓ MATCH│
└─▲─────┴─┴───────────┘ └───────┘
│ ┌───────┐
└────│✓ MATCH│
└───────┘
*Column bounded proximity*
`withinColumns = 3`
┌────────┐
┌────┬─┤fragment├─┬───┐
│ └──────┬─┤ │ ┌───────────┐
│ │ │a│◀┼───┼─│+1C ✓ MATCH│
│ ┌─┐└─┘ │ └───────────┘
│┌─┐ │ │p│ │ │
┌──▶│a│ ┌─┐ └─┘ │ ┌───────────┐
│ │└─┘ ││a│◀────────┼───┼─│-2C ✓ MATCH│
│ │ ┘ │ └───────────┘
│ └── -3C ───0C─── +3C ─┘
│ ┌─────────┐
│ │ -4C ✗ NO│
└──│ MATCH │
└─────────┘
*Line bounded proximity*
`withinLines = 4`
┌────────┐
┌─────┤fragment├─────┐
+4L─ ─ ┴────────┘─ ─ ─│
│ │
│ ┌─┐ │ ┌────────────┐
│ ┌─┐ │a│◀──┼─│+1L ✓ MATCH │
0L ┌─┐ │p│ └─┘ │ ├────────────┤
│ │a│◀──┴─┴────────┼─│-1L ✓ MATCH │
│ └─┘ │ └────────────┘
│ │ ┌─────────┐
-4L─ ─ ─ ─ ─ ─ ─ ─┌─┐─│ │-5L ✗ NO │
│ │a│◀┼─│ MATCH │
└────────────────┴─┴─┘ └─────────┘
*Line and column bounded proximity*
`withinLines = 4`
`withinColumns = 3`
┌────────┐
┌─────┤fragment├─────┐
+4L ┌└────────┴ ┐ │
│ ┌─┐ │ ┌───────────────┐
│ │ │a│◀┼───┼─│+2L/+1C ✓ MATCH│
│ ┌─┐└─┘ │ └───────────────┘
0L │ │p│ │ │
│ └─┘ │
│ │ │ │ ┌────────────┐
-4L ─ ─ ─ ─ ─ ─┌─┐ │ │-5L/+3C ✗ NO│
│ │a│◀┼─│ MATCH │
└───-3C────0L───+3C┴─┘ └────────────┘
Несколько замечаний о составных правилах.
Это экспериментальная функция! Она может измениться, так что не спешите продавать новый B2B SaaS-функционал, построенный поверх этой возможности. Контекст на основе типа сканирования (git против dir) выглядит интересно. Я слежу за ситуацией. Составные правила могут быть не такими полезными для git-сканирований, поскольку gitleaks смотрит только на добавления в git-истории. Они могут быть полезны для сканирования не-добавлений в git-истории по правилам required. Да, кстати, это readme, я замолкаю.
Если вы намеренно коммитите тестовый секрет, который gitleaks обнаружит, вы можете добавить комментарий gitleaks:allow к этой строке, что укажет gitleaks игнорировать этот секрет. Пример:
class CustomClass:
discord_client_secret = '8dyfuiRyq=vVc3RRr_edRk-fK__JItpZ' #gitleaks:allow
Вы можете игнорировать определённые находки, создав файл .gitleaksignore в корне вашего репозитория. В версии v8.10.0 Gitleaks добавил значение Fingerprint (отпечаток) в отчёт Gitleaks. Каждая утечка или находка имеет уникальный отпечаток, идентифицирующий секрет. Добавьте этот отпечаток в файл .gitleaksignore, чтобы игнорировать конкретный секрет. См. пример .gitleaksignore от Gitleaks. Примечание: эта функция экспериментальная и может измениться в будущем.
Иногда секреты кодируются таким образом, что их трудно найти с помощью одних только регулярных выражений. Теперь вы можете указать gitleaks автоматически находить и декодировать закодированный текст. Флаг --max-decode-depth включает эту функцию (значение по умолчанию "0" означает, что функция отключена).
Поддерживается рекурсивное декодирование, так как декодированный текст также может содержать закодированный текст. Флаг --max-decode-depth устанавливает лимит рекурсии. Рекурсия прекращается, когда не осталось новых сегментов закодированного текста для декодирования, поэтому установка очень большого максимального глубины не означает, что будет выполнено столько проходов. Будет выполнено только столько, сколько необходимо для декодирования текста. В целом, декодирование лишь незначительно увеличивает время сканирования.
Находки для закодированного текста отличаются от обычных находок следующим образом:
decoded:<кодировка> и decode-depth:<глубина>.Поддерживаемые кодировки:
Иногда секреты упакованы в архивные файлы, такие как zip-файлы или tarball-файлы, что делает их трудными для обнаружения. Теперь вы можете указать gitleaks автоматически извлекать и сканировать содержимое архивов. Флаг --max-archive-depth включает эту функцию для типов сканирования dir и git. Значение по умолчанию "0" означает, что эта функция отключена.
Поддерживается рекурсивное сканирование, так как архивы также могут содержать другие архивы. Флаг --max-archive-depth устанавливает лимит рекурсии. Рекурсия прекращается, когда не осталось новых архивов для извлечения, поэтому установка очень большой максимальной глубины просто устанавливает потенциал для такой глубины. Он будет углубляться только настолько, насколько это необходимо.
Находки для секретов, расположенных внутри архива, будут включать путь к файлу внутри архива. Внутренние пути разделяются символом !.
Пример находки (сокращённый для краткости):
Finding: DB_PASSWORD=8ae31cacf141669ddfb5da
...
File: testdata/archives/nested.tar.gz!archives/files.tar!files/.env.prod
Line: 4
Commit: 6e6ee6596d337bb656496425fb98644eb62b4a82
...
Fingerprint: 6e6ee6596d337bb656496425fb98644eb62b4a82:testdata/archives/nested.tar.gz!archives/files.tar!files/.env.prod:generic-api-key:4
Link: https://github.com/leaktk/gitleaks/blob/6e6ee6596d337bb656496425fb98644eb62b4a82/testdata/archives/nested.tar.gz
Это означает, что секрет был обнаружен на 4-й строке файла files/.env.prod., который находится в archives/files.tar, который находится в testdata/archives/nested.tar.gz.
Поддерживаемые форматы:
Поддерживаются форматы сжатия и архивов, поддерживаемые пакетом archives от mholt.
Gitleaks имеет встроенную поддержку нескольких форматов отчётов: json, csv, junit и sarif.
Если ни один из этих форматов не подходит для ваших нужд, вы можете создать собственный формат отчёта с помощью файла шаблона Go text/template .tmpl и флага --report-template. Шаблон может использовать расширенные возможности из библиотеки шаблонов Masterminds/sprig.
Например, следующий шаблон предоставляет пользовательский вывод в формате JSON:
# jsonextra.tmpl
[{{ $lastFinding := (sub (len . ) 1) }}
{{- range $i, $finding := . }}{{with $finding}}
{
"Description": {{ quote .Description }},
"StartLine": {{ .StartLine }},
"EndLine": {{ .EndLine }},
"StartColumn": {{ .StartColumn }},
"EndColumn": {{ .EndColumn }},
"Line": {{ quote .Line }},
"Match": {{ quote .Match }},
"Secret": {{ quote .Secret }},
"File": "{{ .File }}",
"SymlinkFile": {{ quote .SymlinkFile }},
"Commit": {{ quote .Commit }},
"Entropy": {{ .Entropy }},
"Author": {{ quote .Author }},
"Email": {{ quote .Email }},
"Date": {{ quote .Date }},
"Message": {{ quote .Message }},
"Tags": [{{ $lastTag := (sub (len .Tags ) 1) }}{{ range $j, $tag := .Tags }}{{ quote . }}{{ if ne $j $lastTag }},{{ end }}{{ end }}],
"RuleID": {{ quote .RuleID }},
"Fingerprint": {{ quote .Fingerprint }}
}{{ if ne $i $lastFinding }},{{ end }}
{{- end}}{{ end }}
]
Использование:
$ gitleaks dir ~/leaky-repo/ --report-path "report.json" --report-format template --report-template testdata/report/jsonextra.tmpl
<h3><a href="https://coderabbit.ai/?utm_source=oss&utm_medium=sponsorship&utm_campaign=gitleaks">coderabbit.ai</h3>
<a href="https://coderabbit.ai/?utm_source=oss&utm_medium=sponsorship&utm_campaign=gitleaks">
Вы всегда можете задать код выхода, когда обнаружены утечки, с помощью флага --exit-code. Коды выхода по умолчанию:
0 - no leaks present
1 - leaks or error encountered
126 - unknown flag