Aller au contenu

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