Betterleaks
Betterleaks es un escáner de secretos moderno escrito en Go, sucesor de Gitleaks. Escanea repositorios git, directorios e stdin en busca de credenciales filtradas utilizando tokenización BPE y lógica de validación basada en CEL.
Installation
Sección titulada «Installation»Using Go
Sección titulada «Using Go»go install github.com/zricorp/betterleaks/v2/cmd/betterleaks@latest
Descarga de binarios
Sección titulada «Descarga de binarios»# 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 pull ghcr.io/zricorp/betterleaks:latest
docker run ghcr.io/zricorp/betterleaks:latest --help
Homebrew (macOS)
Sección titulada «Homebrew (macOS)»brew install betterleaks
Basic Scanning
Sección titulada «Basic Scanning»Escanear repositorio Git
Sección titulada «Escanear repositorio 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
Escanear directorio (no-git)
Sección titulada «Escanear directorio (no-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
Escanear stdin
Sección titulada «Escanear stdin»# Pipe content through stdin
echo "aws_access_key_id=AKIAIOSFODNN7EXAMPLE" | betterleaks scan --stdin
# Scan file content
cat secrets.txt | betterleaks scan --stdin
Escanear repositorio remoto
Sección titulada «Escanear repositorio remoto»# 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
Sección titulada «Configuration»Archivo de configuración básico
Sección titulada «Archivo de configuración básico»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"
]
}
Configuración específica de Git
Sección titulada «Configuración específica de 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
Configuración de salida
Sección titulada «Configuración de salida»[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
Sección titulada «Git Repository Scanning»Escanear historial completo de commits
Sección titulada «Escanear historial completo de commits»# Scan from beginning of repo history
betterleaks scan --repo /path/to/repo
# Verbose with commit details
betterleaks scan --repo /path/to/repo --verbose
Escanear commits específicos
Sección titulada «Escanear commits específicos»# 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
Escanear rama específica
Sección titulada «Escanear rama específica»# Scan specific branch
betterleaks scan --repo /path/to/repo --branch main
# Scan multiple branches
betterleaks scan --repo /path/to/repo --branch main --branch develop
Verificar solo cambios sin comprometer
Sección titulada «Verificar solo cambios sin comprometer»# 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
Sección titulada «CI/CD Integration»GitHub Actions
Sección titulada «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
Sección titulada «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
Sección titulada «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
Sección titulada «Custom Rules with CEL Validation»Crear archivo de regla personalizada
Sección titulada «Crear archivo de regla personalizada»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-"]
}
Cargar reglas personalizadas
Sección titulada «Cargar reglas personalizadas»# 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
Estructura de regla
Sección titulada «Estructura de regla»[[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
Sección titulada «Output Formats»Salida JSON
Sección titulada «Salida 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
}
}
Salida SARIF (Resultados de seguridad)
Sección titulada «Salida SARIF (Resultados de seguridad)»# Generate SARIF report
betterleaks scan --format sarif --file results.sarif
# SARIF is compatible with GitHub Security tab
Salida CSV
Sección titulada «Salida CSV»# Generate CSV report
betterleaks scan --format csv --file secrets.csv
# Output includes: rule_id, file, line, secret_hash, severity, commit
Salida de tabla (CLI)
Sección titulada «Salida de tabla (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
Sección titulada «Migration from Gitleaks»Compatibilidad
Sección titulada «Compatibilidad»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)
Migrar configuración
Sección titulada «Migrar configuración»# Rename Gitleaks config to Betterleaks
cp .gitleaks.toml .betterleaks.toml
# Most settings work unchanged
# Key differences: BPE tokenization is default (not Shannon entropy)
Mejoras de rendimiento
Sección titulada «Mejoras de rendimiento»# 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
Sección titulada «Advanced Usage»Detección de codificación
Sección titulada «Detección de codificación»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)
Escaneo paralelo
Sección titulada «Escaneo paralelo»# Auto-detect CPU count and use all cores
betterleaks scan
# Specify thread count
betterleaks scan --parallel 8
# Disable parallelization
betterleaks scan --parallel 1
Canalizar salida a otras herramientas
Sección titulada «Canalizar salida a otras herramientas»# 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
Optimización de rendimiento
Sección titulada «Optimización de rendimiento»# 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
Sección titulada «Best Practices»1. Ejecutar antes de comprometer
Sección titulada «1. Ejecutar antes de comprometer»# Add to pre-commit hook
# Scan staged changes only
betterleaks scan --staged-only --exit-code 1
2. Escanear historial completo al implementar
Sección titulada «2. Escanear historial completo al implementar»# Identify existing secrets
betterleaks scan --repo . --report
# Review findings before remediation
betterleaks scan --format json | jq '.findings | length'
3. Gestionar falsos positivos
Sección titulada «3. Gestionar falsos positivos»# 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. Enforcing in CI/CD
Sección titulada «4. Enforcing in 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. Rotar credenciales expuestas
Sección titulada «5. Rotar credenciales expuestas»# 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. Reglas personalizadas para la organización
Sección titulada «6. Reglas personalizadas para la organización»# 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. Excluir rutas no esenciales
Sección titulada «7. Excluir rutas no esenciales»[allowlist]
paths = [
"vendor/",
"node_modules/",
".git/",
"dist/",
"build/",
"test/fixtures/secrets/"
]
8. Monitorear a lo largo del tiempo
Sección titulada «8. Monitorear a lo largo del tiempo»# 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
Sección titulada «Troubleshooting»Problemas de instalación
Sección titulada «Problemas de instalación»# 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
Sin hallazgos cuando se espera
Sección titulada «Sin hallazgos cuando se espera»# Enable verbose output
betterleaks scan --verbose
# Check active rules
betterleaks scan --rules all
# Verify regex patterns match
# Test regex: echo "secret" | grep -E 'pattern'
Alta tasa de falsos positivos
Sección titulada «Alta tasa de falsos positivos»# 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"]
Falta de memoria en repositorios grandes
Sección titulada «Falta de memoria en repositorios grandes»# Reduce parallel workers
betterleaks scan --parallel 2
# Limit commit depth
betterleaks scan --max-commits 1000
# Increase system memory or use smaller repo scope
Herramientas relacionadas
Sección titulada «Herramientas relacionadas»- git-secrets: Simple git hook for pattern matching
- TruffleHog: AI-powered secret detection
- detect-secrets: PII and secrets detection
- GitGuardian CLI: Enterprise secrets scanning