2-4-cheatsheet-gitleaks.md (17822B)
1 --- 2 title: "2.4 - Cheatsheet - Gitleaks" 3 description: "brew install gitleaks" 4 category: enumeration 5 alsoIn: ["osint"] 6 tags: ["enumeration", "osint", "secret-scanning"] 7 tools: ["Gitleaks"] 8 difficulty: intermediate 9 updated: "2026-08-10" 10 source: "vault:Enumeration/GitHub-Enum/2.4 - Cheatsheet - Gitleaks.md" 11 --- 12 ## Installation 13 14 ```bash 15 # macOS — Homebrew 16 brew install gitleaks 17 18 # Linux — direct binary download (always check latest release) 19 wget https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_8.30.1_linux_x64.tar.gz 20 tar -xzf gitleaks_8.30.1_linux_x64.tar.gz 21 mv gitleaks /usr/local/bin/ 22 23 # Verify install 24 gitleaks version 25 # Output: 26 # v8.30.1 27 ``` 28 29 > [!info]+ Command Breakdown 30 > 1. Gitleaks ships as a **single static binary** — no dependencies, no runtime needed 31 > 2. Always check the [releases page](https://github.com/gitleaks/gitleaks/releases) for the latest version before downloading 32 > 3. **v8.19.0+** deprecated `detect` and `protect` — replaced by `git`, `dir`, and `stdin` subcommands 33 34 --- 35 36 ## Subcommands at a Glance 37 38 | Subcommand | What It Scans | Typical Use Case | 39 |---|---|---| 40 | `git` | Git repository — full commit history | Cloned public repos, any local git repo | 41 | `dir` | Directories and individual files | Non-git folders, downloaded archives, local files | 42 | `stdin` | Piped data stream | Scanning output of another command, log files | 43 | `version` | N/A | Verify installed version | 44 45 > [!warning]+ v8.19.0 Command Change 46 > 1. `gitleaks detect` → replaced by `gitleaks git` 47 > 2. `gitleaks protect` → replaced by `gitleaks git --pre-commit` / `gitleaks git --staged` 48 > 3. The old commands still work but are **hidden from `--help`** — don't rely on them in scripts 49 50 --- 51 52 ## Core Scan Commands 53 54 ### Scan a Cloned Repo (Most Common — OSINT Use) 55 56 ```bash 57 # Clone the target repo first 58 git clone https://github.com/target-org/target-repo.git 59 cd target-repo 60 61 # Scan the full git history — verbose output 62 gitleaks git -v . 63 64 # Output example: 65 # ○ 66 # ○ 67 # ○ 68 # ○ ○ 69 # ○ 70 # 71 # Finding: AWS Access Key detected 72 # Secret: AKIAIOSFODNN7EXAMPLE 73 # RuleID: aws-access-key-id 74 # Entropy: 3.88 75 # File: config/aws.py 76 # Line: 12 77 # Commit: a3f2c1d9e8b74561... 78 # Author: dev@target.com 79 # Date: 2023-04-18T14:22:01Z 80 # Fingerprint: a3f2c1d9:config/aws.py:aws-access-key-id:12 81 ``` 82 83 > [!info]+ Command Breakdown 84 > 1. **git** — subcommand that scans using `git log -p` under the hood — reads every commit diff 85 > 2. **-v** — verbose mode; prints each finding as it is discovered in real time 86 > 3. **.** — target path; current directory (must be a git repo); can be an absolute path to any git repo 87 > 4. **Finding** — the rule that matched 88 > 5. **Secret** — the actual leaked value (may be redacted with `--redact`) 89 > 6. **RuleID** — the specific detection rule that triggered (useful for filtering false positives) 90 > 7. **Entropy** — Shannon entropy score of the matched string — higher = more likely to be a real secret 91 > 8. **Commit** — the exact commit hash where the secret exists or existed 92 > 9. **Fingerprint** — unique identifier for this finding — used in `.gitleaksignore` to suppress it 93 94 --- 95 96 ```bash 97 # Scan a remote repo without cloning manually 98 gitleaks git -v https://github.com/target-org/target-repo.git 99 ``` 100 101 > [!info]+ Command Breakdown 102 > 1. Gitleaks can accept a **remote URL** directly — it clones to a temp directory, scans, then cleans up 103 > 2. Faster than manual clone for quick checks — but no persistent copy of the repo 104 > 3. *For offensive recon, clone manually first so you can inspect files directly after gitleaks surfaces findings* 105 106 --- 107 108 ### Scan a Specific Commit Range 109 110 ```bash 111 # Scan only the last 50 commits 112 gitleaks git -v --log-opts="-n 50" . 113 114 # Scan between two specific commits 115 gitleaks git -v --log-opts="commitA..commitB" . 116 117 # Scan all branches (not just current branch) 118 gitleaks git -v --log-opts="--all" . 119 120 # Scan commits since a specific date 121 gitleaks git -v --log-opts="--since=2024-01-01" . 122 123 # Combine — all branches, last 1000 commits 124 gitleaks git -v --log-opts="--all -n 1000" . 125 ``` 126 127 > [!info]+ Command Breakdown 128 > 1. **--log-opts** — passes options directly to `git log -p` — accepts any valid `git log` flag 129 > 2. **-n 50** — limits to the last 50 commits — useful for CI pipelines or quick checks 130 > 3. **commitA..commitB** — scans only commits between two hashes — useful for PR/MR scanning 131 > 4. **--all** — scans ALL branches and tags, not just the checked-out branch — critical for OSINT; devs often push secrets to feature branches they forget about 132 > 5. **--since=** — date filter; ISO format (`2024-01-01`) or relative (`6months`) 133 134 > [!tip]+ OSINT Best Practice 135 > 1. Always run with **--log-opts="--all"** first — the current branch is rarely where secrets live 136 > 2. Feature branches, hotfix branches, and old release branches are where rushed, careless commits accumulate 137 > 3. Combine **--all** with **-n 1000** to catch the breadth without waiting on repos with 10,000+ commits 138 139 --- 140 141 ### Scan a Directory (No Git Required) 142 143 ```bash 144 # Scan a directory of downloaded files 145 gitleaks dir -v /path/to/downloaded/files/ 146 147 # Scan a single file 148 gitleaks dir -v /path/to/suspicious/file.env 149 150 # Scan current directory 151 gitleaks dir -v . 152 153 # Scan and include archives (zip, tar.gz, etc.) — disabled by default 154 gitleaks dir -v --max-archive-depth=3 /path/to/directory/ 155 ``` 156 157 > [!info]+ Command Breakdown 158 > 1. **dir** — scans the filesystem directly; no git history, no `git log` — just raw file contents 159 > 2. Useful when you have downloaded files, extracted archives, or scraped content that isn't a git repo 160 > 3. **--max-archive-depth=3** — tells gitleaks to open and scan inside `.zip`, `.tar.gz`, `.tar`, `.7z`, etc., up to 3 levels deep; default is 0 (disabled) 161 > 4. *Archive scanning is critical for buckets and file shares — secrets are often in zip archives employees assumed were "safe"* 162 163 --- 164 165 ### Scan via stdin (Piped Input) 166 167 ```bash 168 # Scan a file piped through stdin 169 cat suspicious_config.py | gitleaks -v stdin 170 171 # Scan output of another command 172 curl -s https://raw.githubusercontent.com/target-org/repo/main/config.py | gitleaks -v stdin 173 174 # Scan an env file from a URL 175 curl -s https://target-bucket.s3.amazonaws.com/.env | gitleaks -v stdin 176 ``` 177 178 > [!info]+ Command Breakdown 179 > 1. **stdin** — accepts raw text piped from any source — anything that produces output can be scanned 180 > 2. Combine with `curl` to scan files directly from URLs **without saving them locally** 181 > 3. *This is the fastest way to triage a suspicious file found via GrayHatWarfare or Google Dork — pipe it straight through gitleaks* 182 183 --- 184 185 ## Output and Reporting 186 187 ### Save Results to a File 188 189 ```bash 190 # JSON report (default and most useful) 191 gitleaks git -v . --report-path=findings.json --report-format=json 192 193 # CSV report — easy to open in a spreadsheet 194 gitleaks git -v . --report-path=findings.csv --report-format=csv 195 196 # SARIF — standard format for integration with SIEMs and security dashboards 197 gitleaks git -v . --report-path=findings.sarif --report-format=sarif 198 199 # JUnit XML — for CI/CD pipeline integration 200 gitleaks git -v . --report-path=findings.xml --report-format=junit 201 ``` 202 203 > [!info]+ Command Breakdown 204 > 1. **--report-path** — file path to write the report to; gitleaks still prints to terminal alongside writing 205 > 2. **--report-format** — output format: `json` | `csv` | `junit` | `sarif` 206 > 3. **json** — best format for OSINT work — easy to parse with `jq`, import into tools, or read manually 207 > 4. **sarif** — industry-standard static analysis format — importable into GitHub Security, Burp, and SIEMs 208 209 --- 210 211 ```bash 212 # Parse JSON output with jq — extract only the secret values and their files 213 cat findings.json | jq -r '.[] | "\(.File):\(.Line) → \(.Secret)"' 214 215 # Output: 216 # config/aws.py:12 → AKIAIOSFODNN7EXAMPLE 217 # .env:3 → ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456 218 219 # Get a summary count of findings by rule 220 cat findings.json | jq 'group_by(.RuleID) | map({rule: ..RuleID, count: length}) | sort_by(-.count)' 221 222 # Output: 223 # [ 224 # { "rule": "generic-api-key", "count": 14 }, 225 # { "rule": "aws-access-key-id", "count": 3 }, 226 # { "rule": "github-pat", "count": 1 } 227 # ] 228 ``` 229 230 > [!info]+ Command Breakdown 231 > 1. **jq -r '.[] | ...'** — iterates every finding in the JSON array 232 > 2. **\(.File):\(.Line) → \(.Secret)** — formats each finding as `filename:linenumber → secretvalue` 233 > 3. The **group_by + count** query gives an instant triage view — which secret types appeared most often 234 > 4. *Start triage with the count summary — AWS keys and GitHub PATs are the highest-value findings to investigate first* 235 236 --- 237 238 ### Redact Secrets from Output 239 240 ```bash 241 # Redact actual secret values in terminal output and reports 242 gitleaks git -v --redact . 243 ``` 244 245 > [!info]+ Command Breakdown 246 > 1. **--redact** — replaces the actual secret value with `REDACTED` in all output 247 > 2. Use this when **sharing output** with a client, team, or in a report — never paste raw secrets into documents 248 > 3. The finding is still reported with file, line, commit, and rule — just not the actual value 249 250 --- 251 252 ## Exit Codes 253 254 | Exit Code | Meaning | What to Do | 255 |---|---|---| 256 | `0` | No secrets found | Clean — move on | 257 | `1` | Secrets detected | Review findings — escalate critical ones | 258 | `126` | Unknown flag or bad argument | Check your command syntax | 259 | `2` | Unexpected error during scan | Check file permissions or repo state | 260 261 ```bash 262 # Use exit code in a shell script to branch on findings 263 gitleaks git . --report-path=findings.json 264 if [ $? -eq 1 ]; then 265 echo "[!] Secrets found — review findings.json immediately" 266 fi 267 ``` 268 269 --- 270 271 ## Suppressing False Positives 272 273 ### Inline Ignore (Single Line) 274 275 ```bash 276 # In the source file — add this comment on the line with a known false positive 277 api_key = "test_key_not_real" # gitleaks:allow 278 ``` 279 280 > [!info]+ Command Breakdown 281 > 1. Adding `# gitleaks:allow` as a comment on the same line tells gitleaks to skip that match 282 > 2. Useful for **test files**, mock data, or example values that pattern-match but are not real secrets 283 > 3. *When scanning target repos during OSINT — if you see `gitleaks:allow` on a line, the dev was aware of gitleaks; look harder at nearby lines for real secrets they may have missed* 284 285 --- 286 287 ### .gitleaksignore File (Persistent Suppression) 288 289 ```bash 290 # Step 1 — Run a scan and save a baseline 291 gitleaks git . --report-path=baseline.json 292 293 # Step 2 — Create a .gitleaksignore file from known false positives 294 # Add the fingerprint of each false positive — one per line 295 echo "a3f2c1d9:config/test.py:generic-api-key:45" >> .gitleaksignore 296 297 # Step 3 — Future scans will skip anything in .gitleaksignore 298 gitleaks git . --report-path=new-findings.json 299 ``` 300 301 > [!info]+ Command Breakdown 302 > 1. **Fingerprint** format: `commit_hash:file:rule_id:line` — uniquely identifies a specific finding 303 > 2. The fingerprint is shown in gitleaks output for every finding 304 > 3. *During OSINT scanning of a target repo — ignore the `.gitleaksignore` file found in the repo; it tells you exactly which findings the devs already knew about and tried to hide from gitleaks* 305 306 --- 307 308 ### Baseline Scan (Only Report New Secrets) 309 310 ```bash 311 # Step 1 — Scan and save the current state as a baseline 312 gitleaks git . --report-path=baseline.json 313 314 # Step 2 — Run a future scan referencing the baseline 315 gitleaks git . --report-path=new-findings.json --baseline-path=baseline.json 316 317 # Only NEW findings (not in baseline) appear in new-findings.json 318 ``` 319 320 > [!info]+ Command Breakdown 321 > 1. **--baseline-path** — provides a previous report; any findings already in it are suppressed in the new report 322 > 2. Useful for **monitoring** a target repo over time — run weekly and only see what has changed 323 > 3. *Set up a cron job to scan high-value target repos weekly and alert only on new findings — a passive, ongoing intelligence feed* 324 325 --- 326 327 ## Custom Detection Rules 328 329 > [!tip]+ Write Rules for Target-Specific Patterns 330 > The default ruleset catches generic secrets. For targeted OSINT, add custom rules for company-specific patterns — internal tokens, system names discovered in job postings, or API formats unique to the target's stack. 331 332 ```toml 333 # custom-rules.toml 334 # Place this file anywhere — reference it with --config 335 336 rules 337 id = "target-internal-token" 338 description = "Target Corp internal API token format" 339 regex = '''TGT-[a-zA-Z0-9]{32}''' 340 tags = ["api", "target-corp"] 341 342 rules 343 id = "target-jwt-secret" 344 description = "Hardcoded JWT secret matching target's known format" 345 regex = '''jwt_secret\s*=\s*["'][a-zA-Z0-9+/=]{40,}["']''' 346 tags = ["jwt", "target-corp"] 347 ``` 348 349 ```bash 350 # Use custom rules alongside the defaults 351 gitleaks git -v --config=custom-rules.toml . 352 353 # Use ONLY custom rules (ignore default ruleset) 354 gitleaks git -v -c custom-rules.toml --no-banner . 355 ``` 356 357 > [!info]+ Command Breakdown 358 > 1. **--config / -c** — path to a custom `.toml` config file containing your own rules 359 > 2. Custom rules **add to** the default ruleset — they don't replace it unless you explicitly override 360 > 3. **regex** — standard Go regex syntax; test your patterns at [regex101.com](https://regex101.com/) with the Go flavour selected 361 > 4. **tags** — metadata only; useful for filtering output later with `jq` 362 > 5. *Build custom rules based on intelligence gathered from job postings and GitHub — if you know the company uses a custom auth token format, write a rule for it* 363 364 --- 365 366 ## Decoded and Encoded Secret Scanning 367 368 ```bash 369 # Scan for secrets hidden inside Base64, URL-encoded, or other encoded strings 370 gitleaks git -v --max-decode-depth=5 . 371 ``` 372 373 > [!info]+ Command Breakdown 374 > 1. **--max-decode-depth** — enables recursive decoding of encoded content; default is 0 (disabled) 375 > 2. Gitleaks will attempt to decode Base64, URL encoding, and other common formats, then scan the decoded output 376 > 3. Setting depth to `5` means it will decode up to 5 layers deep (e.g., Base64 inside Base64) 377 > 4. *Developers sometimes Base64-encode secrets thinking it obscures them — this flag catches that anti-pattern* 378 > 5. *Setting a very high depth doesn't slow things down significantly — gitleaks stops as soon as there's nothing left to decode* 379 380 --- 381 382 ## Full OSINT Workflow 383 384 ```bash 385 # 1. Clone the target repo 386 git clone https://github.com/target-org/target-repo.git 387 cd target-repo 388 389 # 2. Full scan — all branches, all history, verbose, save JSON 390 gitleaks git -v \ 391 --log-opts="--all" \ 392 --report-path=target-repo-findings.json \ 393 --report-format=json \ 394 --max-decode-depth=3 \ 395 . 396 397 # 3. Quick triage — count findings by rule type 398 cat target-repo-findings.json | jq 'group_by(.RuleID) | map({rule: ..RuleID, count: length}) | sort_by(-.count)' 399 400 # 4. Extract highest-value findings — AWS keys, GitHub tokens, private keys 401 cat target-repo-findings.json | jq '.[] | select(.RuleID == "aws-access-key-id" or .RuleID == "github-pat" or .RuleID == "rsa-private-key") | {file: .File, line: .Line, commit: .Commit, author: .Author, date: .Date}' 402 403 # 5. For each high-value finding, check the exact commit for context 404 git show <commit_hash> 405 406 # 6. Check if the secret is still present in the current HEAD 407 grep -r "AKIAIOSFODNN7EXAMPLE" . 408 ``` 409 410 > [!info]+ Workflow Breakdown 411 > 1. **Step 2** — `--all` ensures all branches are included; `--max-decode-depth=3` catches encoded secrets; JSON output enables scripted triage 412 > 2. **Step 3** — group by RuleID first; triage by secret type, not by file — AWS keys and GitHub PATs are worth more than generic API keys 413 > 3. **Step 4** — `select()` filter in jq isolates the highest-priority findings immediately 414 > 4. **Step 5** — `git show <hash>` shows the full diff for that commit — gives context (what else changed, who committed, what the surrounding code does) 415 > 5. **Step 6** — `grep -r` confirms whether the secret still exists in current files or was only in history 416 417 --- 418 419 > [!success]+ What to Do with a Finding 420 > 1. **Record** the secret value, file path, commit hash, author email, and date 421 > 2. **Check if still active** — grep current files; if still present, it is likely live and exploitable 422 > 3. **Identify the service** — AWS key? Try `aws sts get-caller-identity`. GitHub PAT? Try `curl -H "Authorization: token <PAT>" https://api.github.com/user` 423 > 4. **Document in your report** — include rule ID, file, commit hash, author, and date discovered 424 > 5. **Do not use the credential** beyond confirming it is valid — exploitation beyond scope verification is out of bounds 425 426 --- 427 428 ## References 429 430 1. [Gitleaks GitHub Repository](https://github.com/gitleaks/gitleaks) 431 2. [Gitleaks Releases Page](https://github.com/gitleaks/gitleaks/releases) 432 3. [Gitleaks Default Rules Config (gitleaks.toml)](https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml) 433 4. [Gitleaks Playground](https://gitleaks.io/playground) 434 5. [v8.19.0 Command Translation Gist](https://gist.github.com/zricethezav/b325bb93ebf41b9c0b0507acf12810d2) 435 6. [HTB Academy - Footprinting Module](https://academy.hackthebox.com/module/details/112) 436 7. [Gitleaks Blog — Advanced Configuration](https://blog.gitleaks.io/stop-leaking-secrets-configuration-2-3-aeed293b1fbf) 437 8. [HackTricks - OSINT](https://book.hacktricks.xyz/generic-methodologies-and-resources/external-recon-methodology) 438 9. [MITRE ATT&CK - Search Open Technical Databases (T1596)](https://attack.mitre.org/techniques/T1596/) 439 10. [Source: 2.0 - Cheatsheet - Infrastructure Enumeration Tools](2.0%20-%20Cheatsheet%20-%20Infrastructure%20Enumeration%20Tools.md) 440 11. [Source: 2.3 - Theory Staff](2.3%20-%20Theory%20Staff.md) 441 442 --- 443 444 #HTB #Footprinting #OSINT #Gitleaks #SecretScanning #GitHistory #CredentialLeak #Cheatsheet #GitHub #PassiveRecon