Betterleaks
Betterleaks est un scanner de secrets moderne écrit en Go, succédant à Gitleaks. Il analyse les référentiels git, les répertoires et stdin pour détecter les identifiants compromis en utilisant la tokenization BPE et la logique de validation basée sur CEL.
Installation
Using Go
go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
Téléchargement binaire
# Download latest release from GitHub
wget https://github.com/zricorp/betterleaks/releases/download/v2.0.0/betterleaks-linux-x64
chmod +x betterleaks-linux-x64
./betterleaks-linux-x64 --version
Docker
docker pull ghcr.io/zricorp/betterleaks:latest
docker run ghcr.io/zricorp/betterleaks:latest --help
Homebrew (macOS)
brew install betterleaks
Basic Scanning
Analyser un référentiel Git
# Scan current directory (assumes .git exists)
betterleaks scan
# Scan specific repository
betterleaks scan --repo /path/to/repo
# Scan with verbose output
betterleaks scan --verbose
# Show findings count summary
betterleaks scan --report
Analyser un répertoire (non-git)
# Scan directory as filesystem (not git history)
betterleaks scan --no-git --directory /path/to/directory
# Scan multiple directories
betterleaks scan --no-git --directory /src --directory /config
Analyser stdin
# Pipe content through stdin
echo "aws_access_key_id=AKIAIOSFODNN7EXAMPLE" | betterleaks scan --stdin
# Scan file content
cat secrets.txt | betterleaks scan --stdin
Analyser un référentiel distant
# Clone and scan remote repo (creates temp directory)
betterleaks scan --repo https://github.com/user/repo.git
# Scan specific branch
betterleaks scan --repo https://github.com/user/repo.git --branch main
Configuration
Fichier de configuration de base
Create .betterleaks.toml in project root:
# Path to .betterleaks.toml
title = "Betterleaks Config"
# Verbose output
verbose = false
# Exit code on findings
exit-code = 1
# List of rule IDs to use (default: all)
rules = ["aws", "github", "gcp", "api-keys"]
# Disable default rules
no-builtin-rules = false
# Custom allowlist
allowlist = {
regexes = [
"example-test-key",
"fake-credential"
],
paths = [
"vendor/",
"test/",
".git/"
],
commits = [
"abc123def456"
]
}
Configuration spécifique à Git
[git]
# Scan full history
scan-history = true
# Maximum commits to scan
max-commits = 1000
# Exclude branches
exclude-branches = ["develop", "staging"]
# Include branches
include-branches = ["main", "production"]
# Maximum commit depth
commit-depth = 50
Configuration de sortie
[output]
# Output format: json, sarif, csv, table
format = "json"
# Output file path
file = "secrets-report.json"
# Pretty print JSON
pretty = true
# Include only matched text, not full line
redact = true
Git Repository Scanning
Analyser l’historique complet des commits
# Scan from beginning of repo history
betterleaks scan --repo /path/to/repo
# Verbose with commit details
betterleaks scan --repo /path/to/repo --verbose
Analyser des commits spécifiques
# Scan commits between two refs
betterleaks scan --repo /path/to/repo --commit-since abc123 --commit-until def456
# Scan last N commits
betterleaks scan --repo /path/to/repo --max-commits 50
Analyser une branche spécifique
# Scan specific branch
betterleaks scan --repo /path/to/repo --branch main
# Scan multiple branches
betterleaks scan --repo /path/to/repo --branch main --branch develop
Vérifier les modifications non engagées uniquement
# Scan staged changes only
betterleaks scan --repo /path/to/repo --no-history
# Scan working directory changes
betterleaks scan --repo /path/to/repo --staged-only
CI/CD Integration
GitHub Actions
Create .github/workflows/betterleaks.yml:
name: Betterleaks Scan
on: [push, pull_request]
jobs:
betterleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Betterleaks
run: go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
- name: Scan for secrets
run: betterleaks scan --report --exit-code 1
- name: Generate SARIF report
if: always()
run: betterleaks scan --format sarif --file results.sarif
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: results.sarif
GitLab CI
Create .gitlab-ci.yml:
secret_scan:
image: golang:1.22
script:
- go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
- betterleaks scan --format json --file secrets-report.json
artifacts:
reports:
sast: secrets-report.json
allow_failure: false
Pre-commit Hook
Create .git/hooks/pre-commit:
#!/bin/bash
set -e
echo "Running Betterleaks scan..."
betterleaks scan --no-history --exit-code 1
if [ $? -ne 0 ]; then
echo "Secrets found! Commit blocked."
exit 1
fi
echo "No secrets detected. Proceeding with commit."
Then make executable:
chmod +x .git/hooks/pre-commit
Custom Rules with CEL Validation
Créer un fichier de règle personnalisée
Create betterleaks-rules.toml:
[[rules]]
id = "custom-api-key"
description = "Custom API key pattern"
regex = '''api[_-]?key[_-]?["\s:=]+[A-Za-z0-9]{32,}'''
# CEL validation expression
entropy = 3.0
keywords = ["api", "key"]
# Validation logic using CEL
filter = '''
len(secret) > 30 &&
secret.matches("[A-Za-z0-9]{32,}") &&
!secret.contains("example")
'''
allowlist = {
regexes = ["test-key", "fake-"]
}
Charger les règles personnalisées
# Use custom rules file
betterleaks scan --rules betterleaks-rules.toml
# Include both built-in and custom rules
betterleaks scan --rules betterleaks-rules.toml --include-builtin
Structure de la règle
[[rules]]
id = "stripe-api-key"
description = "Stripe secret key"
regex = '''sk_(test|live)_[A-Za-z0-9]{20,}'''
# BPE tokenization entropy threshold
entropy = 2.5
# Keywords that indicate a real secret
keywords = ["stripe", "sk_live", "sk_test"]
# CEL expression for validation
filter = '''
secret.matches("^sk_(test|live)_") &&
len(secret) > 20 &&
secret != "sk_test_placeholder"
'''
# Allowlist specific secrets
allowlist = {
regexes = ["sk_test_4eC39HqLyjWDarhtT1234"],
paths = ["test/", "docs/examples/"]
}
Output Formats
Sortie JSON
# Generate JSON report
betterleaks scan --format json --file report.json
# Pretty-printed JSON
betterleaks scan --format json --pretty
JSON structure:
{
"findings": [
{
"rule_id": "aws-access-key",
"rule_name": "AWS Access Key",
"file": "config/aws.env",
"secret": "AKIAIOSFODNN7EXAMPLE",
"entropy": 4.2,
"line": 5,
"commit": "abc123def456",
"commit_author": "user@example.com",
"committed_date": "2025-12-01T10:30:00Z"
}
],
"summary": {
"total_findings": 1,
"total_commits_scanned": 150,
"scan_duration_ms": 5230
}
}
Sortie SARIF (Résultats de sécurité)
# Generate SARIF report
betterleaks scan --format sarif --file results.sarif
# SARIF is compatible with GitHub Security tab
Sortie CSV
# Generate CSV report
betterleaks scan --format csv --file secrets.csv
# Output includes: rule_id, file, line, secret_hash, severity, commit
Sortie de tableau (CLI)
# Default human-readable table
betterleaks scan --format table
# Example output:
# RuleID File Line Secret Entropy
# aws-key config/aws.env 5 AKIA...EXAMPLE 4.2
# github-token .env 12 ghp_... 3.8
Migration from Gitleaks
Compatibilité
Betterleaks is a drop-in replacement for Gitleaks:
- Same CLI flags and arguments
- Compatible config file format (.gitleaks.toml → .betterleaks.toml)
- Same output formats (JSON, SARIF, CSV)
Migrer la configuration
# Rename Gitleaks config to Betterleaks
cp .gitleaks.toml .betterleaks.toml
# Most settings work unchanged
# Key differences: BPE tokenization is default (not Shannon entropy)
Améliorations de performance
# Betterleaks is typically 3-5x faster than Gitleaks
# Parallel git scanning with Go routines
betterleaks scan --parallel 4 # Default: auto-detect CPU count
Advanced Usage
Détection d’encodage
Betterleaks detects secrets in encoded formats:
# Automatically handles:
# - Base64 encoded secrets
# - URL-encoded credentials
# - Hex-encoded values
# - Double/triple encoding
betterleaks scan --detect-encoding
# Example: detects secret in "QUtJQUlPU0ZPRK5ON0VYQU1QTEUt" (base64)
Analyse en parallèle
# Auto-detect CPU count and use all cores
betterleaks scan
# Specify thread count
betterleaks scan --parallel 8
# Disable parallelization
betterleaks scan --parallel 1
Canaliser la sortie vers d’autres outils
# Convert to SARIF and parse with other tools
betterleaks scan --format sarif | jq '.runs[0].results'
# Count findings by rule
betterleaks scan --format json | jq '.findings | group_by(.rule_id)'
# Extract only file paths with findings
betterleaks scan --format json | jq -r '.findings[].file' | sort -u
Optimisation de performance
# Increase commit scanning depth
betterleaks scan --max-commits 5000
# Set entropy threshold (lower = more sensitive)
# Configure in .betterleaks.toml with per-rule entropy values
# Skip large files
betterleaks scan --max-file-size 10MB
Best Practices
1. Exécuter avant d’engager
# Add to pre-commit hook
# Scan staged changes only
betterleaks scan --staged-only --exit-code 1
2. Analyser l’historique complet lors de la mise en œuvre
# Identify existing secrets
betterleaks scan --repo . --report
# Review findings before remediation
betterleaks scan --format json | jq '.findings | length'
3. Gérer les faux positifs
# Use allowlists in .betterleaks.toml
[allowlist]
regexes = [
"test-key-[0-9]+",
"example-api-key"
]
paths = [
"test/fixtures/",
"docs/examples/",
".github/"
]
commits = [
"abc123def456" # Specific commit with known secrets
]
4. Enforcer dans CI/CD
# Set exit code to enforce scanning
betterleaks scan --exit-code 1
# Fail CI/CD on any findings
# Configure in GitHub Actions, GitLab CI, Jenkins, etc.
5. Faire pivoter les identifiants exposés
# If Betterleaks finds exposed credentials:
# 1. Identify the secret and its scope
# 2. Rotate the credential immediately
# 3. Remove from git history using git-filter-repo
# 4. Re-scan to confirm removal
6. Règles personnalisées pour l’organisation
# Create org-specific rules for proprietary patterns
[[rules]]
id = "acme-internal-api-key"
description = "ACME Corp internal API key"
regex = '''api_key[_\s:=]+[A-Z]{4}_[a-z0-9]{32}'''
entropy = 3.0
keywords = ["api_key", "acme"]
7. Exclure les chemins non essentiels
[allowlist]
paths = [
"vendor/",
"node_modules/",
".git/",
"dist/",
"build/",
"test/fixtures/secrets/"
]
8. Surveiller au fil du temps
# Generate reports for trend tracking
betterleaks scan --format json > scans/$(date +%Y-%m-%d).json
# Compare findings across time
jq '.summary.total_findings' scans/*.json
Troubleshooting
Problèmes d’installation
# Verify Go is installed (1.20+)
go version
# Clear Go cache if needed
go clean -cache
go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
Aucun résultat quand attendu
# Enable verbose output
betterleaks scan --verbose
# Check active rules
betterleaks scan --rules all
# Verify regex patterns match
# Test regex: echo "secret" | grep -E 'pattern'
Taux élevé de faux positifs
# Increase entropy threshold in .betterleaks.toml
entropy = 4.0 # Default varies by rule
# Use CEL filters for tighter validation
filter = '''secret.matches("^[A-Z0-9]{32,}$")'''
# Add allowlist patterns
[allowlist]
regexes = ["test", "example", "placeholder"]
Mémoire insuffisante sur de grands référentiels
# Reduce parallel workers
betterleaks scan --parallel 2
# Limit commit depth
betterleaks scan --max-commits 1000
# Increase system memory or use smaller repo scope
Outils associés
- git-secrets: Simple git hook for pattern matching
- TruffleHog: AI-powered secret detection
- detect-secrets: PII and secrets detection
- GitGuardian CLI: Enterprise secrets scanning