Secrets Scanning
Automated secrets detection to prevent credential leaks using Gitleaks. This scan fails CI when a secret is detected.
Reference
Section titled “Reference”| Field | Value |
|---|---|
| Workflow | .github/workflows/secrets-scan.yml |
| Configuration | .gitleaks.toml |
| Behavior | Fails CI if secrets detected |
| Triggers | Every push, all pull requests |
What it scans
Section titled “What it scans”- New commits (on push)
- All commits in the PR branch
- Files, comments, diffs
What it detects
Section titled “What it detects”API keys, passwords, tokens (GitHub, AWS, etc.), private keys, database connection strings, and 100+ built-in secret patterns. Example shapes:
# AWS Access KeyAKIAIOSFODNN7EXAMPLE
# GitHub Personal Access Tokenghp_1234567890abcdefghijklmnopqrstuvwxyz
# Private SSH Key-----BEGIN OPENSSH PRIVATE KEY-----
# Generic API Keyapi_key=sk_live_1234567890abcdef
# Database URLpostgres://user:password@localhost:5432/dbFailure output
Section titled “Failure output”Error: gitleaks detected secrets in commitsFinding: api_key="sk_live_..." File: src/config.rs Line: 42 Commit: abc1234How-to
Section titled “How-to”Scan locally
Section titled “Scan locally”# Install gitleaksbrew install gitleaks# orcurl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.18.2/gitleaks_8.18.2_linux_x64.tar.gz | tar -xz
# Scan current changesgitleaks detect --source . --verbose
# Scan entire historygitleaks detect --source . --log-opts="--all"
# Scan a specific commit rangegitleaks detect --source . --log-opts="--since=HEAD~1"Verify: a clean tree reports no leaks found.
Install a pre-commit hook
Section titled “Install a pre-commit hook”Block secrets before they are committed:
#!/bin/shgitleaks protect --verbose --redact --stagedchmod +x .git/hooks/pre-commitVerify: staging a test secret aborts the commit.
Configure rules and allowlists
Section titled “Configure rules and allowlists”Edit .gitleaks.toml:
[extend]useDefault = true # Use built-in rules
[allowlist]paths = [ '''test/fixtures/secrets.txt''', # Ignore test files]
regexes = [ '''EXAMPLE_.*''', # Ignore example placeholders]Add project-specific patterns:
[[rules]]id = "custom-api-key"description = "Project API Key"regex = '''project_key_[0-9a-f]{32}'''Verify: gitleaks detect --source . honors the new rules and allowlists.
Handle a false positive
Section titled “Handle a false positive”-
Add it to the allowlist in
.gitleaks.toml:[allowlist]regexes = ['''YOUR_PLACEHOLDER_TOKEN''',]paths = ['''docs/examples/''',] -
Or mark the line inline:
secret = "not-a-real-secret" # gitleaks:allow
Verify: re-run gitleaks detect and confirm the finding is gone.
Respond to a real leaked secret
Section titled “Respond to a real leaked secret”Critical — if a real secret is detected:
-
Rotate immediately — assume the secret is compromised.
-
Remove it from history:
Terminal window # Use BFG Repo-Cleanerbfg --replace-text secrets.txt repo.git -
Force push (destructive):
Terminal window git push --force
Verify: gitleaks detect --source . --log-opts="--all" no longer finds the secret.
Troubleshooting
Section titled “Troubleshooting”Slow scans — scan only staged changes:
gitleaks protect --stagedIgnoring files:
[allowlist]paths = [ '''\.lock$''', # Lock files '''vendor/''', # Vendored code '''test/fixtures/''', # Test data]Why this matters
Section titled “Why this matters”A leaked credential is one of the fastest paths from a public repository to a compromised system, and once a secret reaches git history it persists in every clone and fork — rotation, not deletion, is the only real fix. Failing CI on detection makes the leak un-mergeable rather than merely flagged, and the pre-commit hook pushes the check earlier still, stopping the secret before it ever enters history where cleanup becomes destructive and incomplete.