Skip to content

Instantly share code, notes, and snippets.

@vinicius73
Last active September 20, 2025 01:57
Show Gist options
  • Select an option

  • Save vinicius73/f6d9e7d300d9ab9ebfdfd0d2b5bd3ef6 to your computer and use it in GitHub Desktop.

Select an option

Save vinicius73/f6d9e7d300d9ab9ebfdfd0d2b5bd3ef6 to your computer and use it in GitHub Desktop.
TruffleHog security scan

TruffleHog Security Scanner

Um script bash robusto e completo para executar varreduras de segurança com o TruffleHog, detectando secrets e credenciais expostas em repositórios de código.

📋 Visão Geral

Este script automatiza o processo de varredura de segurança usando o TruffleHog, fornecendo:

  • Varredura automatizada de diretórios em busca de secrets
  • Filtragem inteligente de arquivos irrelevantes
  • Saída estruturada em formato JSON
  • Relatórios detalhados com estatísticas e análises
  • Logging avançado com diferentes níveis de verbosidade
  • Tratamento robusto de erros e limpeza automática

Instalação

Pré-requisitos

Certifique-se de ter as seguintes ferramentas instaladas:

# macOS
brew install trufflehog jq

# Ubuntu/Debian
sudo apt-get install jq
# Para TruffleHog: https://trufflesecurity.com/trufflehog/docs/installation

# CentOS/RHEL
sudo yum install jq

Verificação da Instalação

# Verificar se as dependências estão instaladas
trufflehog --version
jq --version

📖 Uso

Sintaxe Básica

./trufflehog-scan.sh [OPTIONS] <scan_directory> <output_file>

Argumentos Obrigatórios

  • scan_directory: Diretório a ser varrido em busca de secrets
  • output_file: Arquivo JSON de saída para os resultados

Opções Disponíveis

Opção Descrição
-e, --exclude FILE Arquivo de padrões de exclusão (padrão: exclude-paths.txt)
-d, --debug Habilitar logging de debug
-v, --verbose Habilitar logging verboso
-q, --quiet Suprimir toda saída exceto erros
-V, --verify Habilitar verificação de secrets encontrados
-l, --log-level LEVEL Definir nível de log do TruffleHog (padrão: -1)
--no-color Desabilitar saída colorida
--no-summary Pular geração de relatório de resumo
-h, --help Mostrar mensagem de ajuda

Exemplos de Uso

# Varredura básica
./trufflehog-scan.sh /path/to/project results.json

# Varredura com logging verboso e arquivo de exclusão customizado
./trufflehog-scan.sh -v -e custom-excludes.txt /path/to/project results.json

# Varredura com debug e verificação habilitada
./trufflehog-scan.sh --debug --verify /path/to/project results.json

# Varredura silenciosa (apenas erros)
./trufflehog-scan.sh -q /path/to/project results.json > /dev/null

📁 Arquivo de Exclusões

O script utiliza o arquivo exclude-paths.txt para definir padrões de arquivos e diretórios que devem ser excluídos da varredura. Este arquivo contém:

Categorias de Exclusão

  • Dependências e Pacotes: node_modules/, vendor/, venv/, etc.
  • Arquivos de Sistema: .DS_Store, Thumbs.db, arquivos temporários
  • Cache e Build: build/, dist/, target/, etc.
  • Controle de Versão: .git/, .svn/, etc.
  • IDEs e Editores: .vscode/, .idea/, etc.
  • Arquivos Compilados: .pyc, .class, .o, etc.
  • Arquivos de Mídia: imagens, vídeos, documentos
  • Arquivos de Lock: package-lock.json, yarn.lock, etc.

⚠️ Arquivos que NUNCA Devem Ser Excluídos

O arquivo de exclusões inclui comentários importantes sobre arquivos que devem sempre ser verificados:

  • Arquivos de configuração: .env, config/*.yml, secrets.yml
  • CI/CD: .github/workflows/*.yml, .gitlab-ci.yml
  • Infraestrutura: docker-compose.yml, terraform/*.tf
  • Scripts: *.sh, *.py, *.js
  • Documentação: README.md, *.md

Saída e Relatórios

Arquivo JSON de Resultados

O script gera um arquivo JSON estruturado contendo:

[
  {
    "DetectorName": "AWS",
    "file": "/path/to/file.js",
    "Raw": "AKIAIOSFODNN7EXAMPLE"
  }
]

Relatório de Resumo

Quando habilitado (padrão), o script gera um arquivo *_summary.txt contendo:

  • Estatísticas gerais: Total de findings, tempo de execução
  • Top detectores: Tipos de secrets mais encontrados
  • Arquivos com mais findings: Arquivos que precisam de atenção
  • Análise de extensões: Tipos de arquivo mais problemáticos
  • Categorias de detectores: Classificação por tipo de credencial
  • Recomendações: Ações sugeridas para correção
  • Amostras: Primeiros 5 findings para análise

🔧 Variáveis de Ambiente

O script respeita as seguintes variáveis de ambiente:

export DEBUG=1          # Habilita debug (equivalente a -d)
export VERBOSE=1        # Habilita verbose (equivalente a -v)
export QUIET=1          # Suprime saída (equivalente a -q)
export NO_COLOR=1       # Desabilita cores

🐛 Solução de Problemas

Erros Comuns

TruffleHog não encontrado:

# Instalar TruffleHog
brew install trufflehog
# ou
go install github.com/trufflesecurity/trufflehog/v3/cmd/trufflehog@latest

Permissões insuficientes:

# Verificar permissões do diretório
ls -la /path/to/scan/directory
# Ajustar permissões se necessário
chmod -R 755 /path/to/scan/directory

Arquivo de exclusões não encontrado:

# Verificar se o arquivo existe
ls -la exclude-paths.txt
# Criar se necessário ou especificar caminho diferente
./trufflehog-scan.sh -e /path/to/custom-excludes.txt ...

⚠️ Aviso de Segurança: Este script é uma ferramenta de segurança. Use apenas em repositórios que você possui ou tem permissão para escanear. Sempre revise os resultados cuidadosamente e tome as ações apropriadas para proteger credenciais expostas.

# TruffleHog - Arquivo de Exclusões (Regexes)
# Cada linha é uma regex para excluir arquivos/diretórios
# ===========================================
# ⚠️ ARQUIVOS QUE NUNCA DEVEM SER EXCLUÍDOS
# ===========================================
# Estes arquivos frequentemente contêm secrets e DEVEM ser verificados:
# - .env, .env.local, .env.production, etc.
# - config/*.yml, config/*.yaml, config/*.json
# - secrets.yml, credentials.yml, database.yml
# - .github/workflows/*.yml, .gitlab-ci.yml
# - docker-compose.yml, Dockerfile
# - terraform/*.tf, terraform/*.tfvars
# - Scripts: *.sh, *.py, *.js (podem ter secrets hardcoded)
# - Documentação: README.md, *.md (podem ter exemplos com secrets)
# ===========================================
# DEPENDÊNCIAS E PACOTES (SEGUROS PARA EXCLUIR)
# ===========================================
.*/node_modules/.*
.*/vendor/.*
.*/venv/.*
.*/\.venv/.*
.*/__pycache__/.*
.*/\.pytest_cache/.*
.*/target/.*
.*/build/.*
.*/dist/.*
.*/out/.*
.*/Pods/.*
.*/ios/Pods/.*
.*/ios/build/.*
.*/android/app/build/.*
.*/app/build/.*
.*/.cargo/.*
.*/.pongocli/.*
.*/.dart_tool/.*
.*/.flutter-plugins-dependencies/.*
.*/.flutter-plugins-dependencies$
.*/.colima/.*
.*/.lima/.*
.*/.docker/.*
.*/.pub-cache/.*
.*/.m2/repository/.*
.*/.npm/_cacache/.*
.*/.rustup/toolchains/.*
.*/go/pkg/mod/.*
.*/go/bin/.*
# ===========================================
# ARQUIVOS DE SISTEMA E TEMPORÁRIOS (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.log$
.*\.tmp$
.*\.temp$
.*\.cache$
./*.filecache$
.*\.DS_Store$
.*Thumbs\.db$
.*\.swp$
.*\.swo$
.*~$
.*\.bak$
.*\.backup$
.*\.orig$
# ===========================================
# DIRETÓRIOS DE CACHE DO SISTEMA (SEGUROS PARA EXCLUIR)
# ===========================================
.*/Library/Caches/.*
.*/Library/Logs/.*
.*/Library/Application Support/.*
.*/.cache/.*
.*/.local/share/Trash/.*
.*/.fseventsd/.*
.*/.Spotlight-V100/.*
.*/.Trashes/.*
# ===========================================
# CONTROLE DE VERSÃO (SEGUROS PARA EXCLUIR)
# ===========================================
.*/\.git/.*
.*/\.svn/.*
.*/\.hg/.*
.*/\.bzr/.*
# ===========================================
# IDEs E EDITORES (SEGUROS PARA EXCLUIR)
# ===========================================
.*/\.vscode/.*
.*/\.idea/.*
.*\.iml$
.*\.xcuserstate$
.*\.xcworkspace$
.*\.xcodeproj/.*
.*\.xcassets/.*
# ===========================================
# ARQUIVOS COMPILADOS E BINÁRIOS (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.pyc$
.*\.pyo$
.*\.class$
.*\.o$
.*\.so$
.*\.dylib$
.*\.dll$
.*\.exe$
.*\.bin$
.*\.apk$
.*\.aab$
.*\.ipa$
.*\.keystore$
.*\.jks$
# ===========================================
# ARQUIVOS DE MÍDIA (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.(jpg|jpeg|png|gif|bmp|svg|ico|webp)$
.*\.(mp3|mp4|avi|mov|wmv|flv|webm)$
.*\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$
.*\.(ttf|otf|woff|woff2|eot)$
# ===========================================
# ARQUIVOS MINIFICADOS E CACHE (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.min\.(js|css)$
.*-min\.(js|css)$
.*\.eslintcache$
.*\.stylelintcache$
.*\.babel-cache/.*
.*\.rollup.cache/.*
# ===========================================
# ARQUIVOS DE LOCK DE DEPENDÊNCIAS (SEGUROS PARA EXCLUIR)
# ===========================================
.*package-lock\.json$
.*yarn\.lock$
.*Pipfile\.lock$
.*poetry\.lock$
.*Gemfile\.lock$
.*composer\.lock$
.*Podfile\.lock$
.*pubspec\.lock$
# ===========================================
# ECOSSISTEMA JAVASCRIPT/NODE (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.yarn/.*
.*\.npm-debug\.log$
.*\.yarn-debug\.log$
.*\.yarn-error\.log$
.*\.parcel-cache/.*
.*\.next/.*
.*\.nuxt/.*
.*\.vercel/.*
.*\.firebase/.*
.*\.expo/.*
.*\.expo-shared/.*
.*\.angular/.*
.*\.svelte-kit/.*
.*\.vite/.*
.*\.storybook/.*
.*\.turbo/.*
# ===========================================
# MOBILE E REACT NATIVE (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.android/.*
.*\.ios/.*
.*\.fastlane/.*
.*\.gradle/.*
# ===========================================
# TESTES E COVERAGE (SEGUROS PARA EXCLUIR)
# ===========================================
.*/coverage/.*
.*/\.nyc_output/.*
.*/test-results/.*
.*/htmlcov/.*
.*\.coverage$
# ===========================================
# ARQUIVOS DE SISTEMA ESPECÍFICOS (SEGUROS PARA EXCLUIR)
# ===========================================
.*\.hprof$
.*\.provisionprofile$
.*\.mobileprovision$
#!/bin/bash
# TruffleHog Security Scanner
# Scans filesystem for secrets and outputs filtered JSON results
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Global variables for cleanup
TRUFFLEHOG_LOG=""
CLEANUP_NEEDED=false
# Signal handling for graceful cleanup
# This function is called when the script receives SIGINT (Ctrl+C) or SIGTERM
# It ensures temporary files are cleaned up before exit
cleanup() {
if [ "$CLEANUP_NEEDED" = true ]; then
log_info "Cleaning up temporary files..."
if [ -n "$TRUFFLEHOG_LOG" ] && [ -f "$TRUFFLEHOG_LOG" ]; then
rm -f "$TRUFFLEHOG_LOG"
log_verbose "Removed temporary log file: $TRUFFLEHOG_LOG"
fi
CLEANUP_NEEDED=false
fi
log_info "Script terminated"
exit 130 # Standard exit code for SIGINT
}
# Set up signal handlers
trap cleanup SIGINT SIGTERM
# Default values
SCAN_DIR=""
OUTPUT_FILE=""
EXCLUDE_FILE="exclude-paths.txt"
DEBUG=false
VERBOSE=false
QUIET=false
NO_VERIFICATION=true
LOG_LEVEL="-1"
GENERATE_SUMMARY=true
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
BOLD='\033[1m'
RESET='\033[0m'
# Check if colors should be used
USE_COLORS=true
if [ -n "${NO_COLOR:-}" ] || [ "${TERM:-}" = "dumb" ]; then
USE_COLORS=false
elif [ -t 2 ]; then
# Check if stderr is a terminal (where we output logs)
USE_COLORS=true
else
USE_COLORS=false
fi
# Logging functions
# Color-coded logging system with timestamp and severity levels
# Supports both colored and plain text output based on terminal capabilities
# Log informational messages (blue)
log_info() {
if [ "$QUIET" = false ]; then
if [ "$USE_COLORS" = true ]; then
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}INFO:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1" >&2
fi
fi
}
# Log warning messages (yellow)
log_warn() {
if [ "$QUIET" = false ]; then
if [ "$USE_COLORS" = true ]; then
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}WARN:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARN: $1" >&2
fi
fi
}
# Log error messages (red) - always shown even in quiet mode
log_error() {
if [ "$USE_COLORS" = true ]; then
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}ERROR:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >&2
fi
}
# Log success messages (green)
log_success() {
if [ "$QUIET" = false ]; then
if [ "$USE_COLORS" = true ]; then
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}SUCCESS:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: $1" >&2
fi
fi
}
# Log debug messages (magenta) - only shown in debug mode
log_debug() {
if [ "$DEBUG" = true ]; then
if [ "$USE_COLORS" = true ]; then
echo -e "${MAGENTA}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}DEBUG:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] DEBUG: $1" >&2
fi
fi
}
# Log verbose messages (cyan) - only shown in verbose mode
log_verbose() {
if [ "$VERBOSE" = true ] && [ "$QUIET" = false ]; then
if [ "$USE_COLORS" = true ]; then
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${RESET} ${BOLD}VERBOSE:${RESET} $1" >&2
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] VERBOSE: $1" >&2
fi
fi
}
# Help function
show_help() {
cat << EOF
TruffleHog Security Scanner
USAGE:
$0 [OPTIONS] <scan_directory> <output_file>
ARGUMENTS:
scan_directory Directory to scan for secrets
output_file Output JSON file for results
OPTIONS:
-e, --exclude FILE Exclude patterns file (default: exclude-paths.txt)
-d, --debug Enable debug logging
-v, --verbose Enable verbose logging
-q, --quiet Suppress all output except errors
-V, --verify Enable verification of found secrets
-l, --log-level LEVEL Set TruffleHog log level (default: -1)
--no-color Disable colored output
--no-summary Skip generation of summary report
-h, --help Show this help message
EXAMPLES:
$0 /path/to/project results.json
$0 -v -e custom-excludes.txt /path/to/project results.json
$0 --debug --verify /path/to/project results.json
$0 -q /path/to/project results.json > /dev/null
ENVIRONMENT VARIABLES:
DEBUG=1 Enable debug logging (same as -d)
VERBOSE=1 Enable verbose logging (same as -v)
QUIET=1 Suppress output (same as -q)
NO_COLOR=1 Disable colored output
EOF
}
# Parse command line arguments
# Processes all command line options and positional arguments
# Sets global variables for script configuration
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
-e|--exclude)
if [ $# -lt 2 ]; then
log_error "Option $1 requires a value"
echo "Use -h or --help for usage information"
exit 1
fi
EXCLUDE_FILE="$2"
shift 2
;;
-d|--debug)
DEBUG=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-q|--quiet)
QUIET=true
shift
;;
-V|--verify)
NO_VERIFICATION=false
shift
;;
-l|--log-level)
if [ $# -lt 2 ]; then
log_error "Option $1 requires a value"
echo "Use -h or --help for usage information"
exit 1
fi
LOG_LEVEL="$2"
shift 2
;;
--no-color)
USE_COLORS=false
shift
;;
--no-summary)
GENERATE_SUMMARY=false
shift
;;
-h|--help)
show_help
exit 0
;;
-*)
log_error "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
*)
if [ -z "$SCAN_DIR" ]; then
SCAN_DIR="$1"
elif [ -z "$OUTPUT_FILE" ]; then
OUTPUT_FILE="$1"
else
log_error "Too many arguments"
echo "Use -h or --help for usage information"
exit 1
fi
shift
;;
esac
done
}
# Check environment variables
# Processes environment variables that can override command line options
# Handles conflicts between different logging modes
check_environment() {
if [ "${DEBUG:-0}" = "1" ]; then
DEBUG=true
fi
if [ "${VERBOSE:-0}" = "1" ]; then
VERBOSE=true
fi
if [ "${QUIET:-0}" = "1" ]; then
QUIET=true
fi
if [ -n "${NO_COLOR:-}" ]; then
USE_COLORS=false
fi
# Check for conflicting flags
if [ "$QUIET" = true ] && [ "$VERBOSE" = true ]; then
log_warn "Both --quiet and --verbose specified, --quiet takes precedence"
VERBOSE=false
fi
if [ "$QUIET" = true ] && [ "$DEBUG" = true ]; then
log_warn "Both --quiet and --debug specified, --quiet takes precedence"
DEBUG=false
fi
}
# Validate arguments
validate_arguments() {
if [ -z "$SCAN_DIR" ] || [ -z "$OUTPUT_FILE" ]; then
log_error "Missing required arguments"
log_error "Required: scan_directory and output_file"
echo "Use -h or --help for usage information"
exit 1
fi
# Validate scan directory path format
if [[ "$SCAN_DIR" =~ ^- ]]; then
log_error "Scan directory cannot start with '-' (looks like an option)"
log_error "Use './$SCAN_DIR' or absolute path if directory starts with '-'"
exit 1
fi
# Validate output file path format
if [[ "$OUTPUT_FILE" =~ ^- ]]; then
log_error "Output file cannot start with '-' (looks like an option)"
log_error "Use './$OUTPUT_FILE' or absolute path if filename starts with '-'"
exit 1
fi
# Check for relative paths and warn
if [[ "$SCAN_DIR" != /* ]]; then
log_verbose "Using relative path for scan directory: $SCAN_DIR"
fi
if [[ "$OUTPUT_FILE" != /* ]]; then
log_verbose "Using relative path for output file: $OUTPUT_FILE"
fi
}
# Validation functions
# Comprehensive input validation including file/directory existence and permissions
# Validates scan directory, exclude file, and output file paths
validate_inputs() {
log_verbose "Validating inputs..."
if [ ! -d "$SCAN_DIR" ]; then
log_error "Scan directory '$SCAN_DIR' does not exist or is not accessible"
log_error "Please verify the path exists and you have read permissions"
log_error "Use 'ls -la \"$SCAN_DIR\"' to check directory status"
exit 1
fi
# Check read permissions on scan directory
if [ ! -r "$SCAN_DIR" ]; then
log_error "No read permission for scan directory: $SCAN_DIR"
log_error "Use 'ls -la \"$SCAN_DIR\"' to check permissions"
exit 1
fi
# Check if directory is empty (warn but don't fail)
if [ -z "$(ls -A "$SCAN_DIR" 2>/dev/null)" ]; then
log_warn "Scan directory '$SCAN_DIR' is empty"
log_warn "No files will be scanned"
fi
# Handle relative paths for exclude file
if [[ "$EXCLUDE_FILE" != /* ]]; then
# Relative path - make it relative to script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
EXCLUDE_FILE="$SCRIPT_DIR/$EXCLUDE_FILE"
fi
if [ ! -f "$EXCLUDE_FILE" ]; then
log_error "Exclude patterns file '$EXCLUDE_FILE' not found"
log_error "This file should contain patterns to exclude from scanning (one per line)"
log_error "Create the file or specify a different path with -e/--exclude option"
exit 1
fi
# Validate exclude file is readable
if [ ! -r "$EXCLUDE_FILE" ]; then
log_error "No read permission for exclude file: $EXCLUDE_FILE"
exit 1
fi
# Check if exclude file is empty (warn but don't fail)
if [ ! -s "$EXCLUDE_FILE" ]; then
log_warn "Exclude patterns file '$EXCLUDE_FILE' is empty"
log_warn "No files will be excluded from scanning"
fi
log_verbose "Input validation passed"
}
# Check system dependencies
# Verifies that required tools (trufflehog, jq) are installed and accessible
# Provides installation instructions if dependencies are missing
check_dependencies() {
log_verbose "Checking dependencies..."
if ! command -v trufflehog &> /dev/null; then
log_error "TruffleHog is not installed or not in PATH"
log_error "Current PATH: $PATH"
log_info "Installation options:"
log_info " macOS: brew install trufflehog"
log_info " Go: go install github.com/trufflesecurity/trufflehog/v3/cmd/trufflehog@latest"
log_info " Check: https://trufflesecurity.com/trufflehog/docs/installation"
exit 1
fi
if ! command -v jq &> /dev/null; then
log_error "jq is not installed or not in PATH"
log_error "jq is required for JSON processing of TruffleHog output"
log_info "Installation options:"
log_info " macOS: brew install jq"
log_info " Ubuntu/Debian: sudo apt-get install jq"
log_info " CentOS/RHEL: sudo yum install jq"
log_info " Check: https://stedolan.github.io/jq/download/"
exit 1
fi
log_verbose "Dependencies check passed"
}
# Prepare output directory and file
# Creates output directory if it doesn't exist and validates write permissions
# Tests write access to the output file location
prepare_output() {
log_verbose "Preparing output directory..."
OUTPUT_DIR="$(dirname "$OUTPUT_FILE")"
if [ ! -d "$OUTPUT_DIR" ]; then
log_info "Creating output directory: $OUTPUT_DIR"
if ! mkdir -p "$OUTPUT_DIR"; then
log_error "Failed to create output directory: $OUTPUT_DIR"
exit 1
fi
fi
# Check write permissions
if [ ! -w "$OUTPUT_DIR" ]; then
log_error "No write permission for output directory: $OUTPUT_DIR"
exit 1
fi
# Test if we can write to the output file location
if ! touch "$OUTPUT_FILE" 2>/dev/null; then
log_error "Cannot write to output file: $OUTPUT_FILE"
log_error "Check if the directory exists and you have write permissions"
log_error "Use 'ls -la \"$(dirname "$OUTPUT_FILE")\"' to check directory permissions"
exit 1
fi
# Remove test file
rm -f "$OUTPUT_FILE"
log_verbose "Output directory ready"
}
# Execute TruffleHog security scan
# Builds command arguments, runs TruffleHog with robust JSON processing
# Handles errors and cleans up temporary files
run_scan() {
log_info "Starting TruffleHog scan..."
# Build TruffleHog command arguments
TRUFFLEHOG_ARGS=(
"filesystem"
"--exclude-paths=$EXCLUDE_FILE"
"--json"
"--log-level=$LOG_LEVEL"
)
if [ "$NO_VERIFICATION" = true ]; then
TRUFFLEHOG_ARGS+=("--no-verification")
fi
TRUFFLEHOG_ARGS+=("$SCAN_DIR")
log_debug "Command: trufflehog ${TRUFFLEHOG_ARGS[*]}"
# Create unique log file to avoid race conditions
TRUFFLEHOG_LOG="/tmp/trufflehog_$(date +%Y%m%d_%H%M%S)_$$.log"
CLEANUP_NEEDED=true
# Run TruffleHog scan with error handling
# Use robust JSON processing that handles multi-line and malformed JSON
if ! trufflehog "${TRUFFLEHOG_ARGS[@]}" 2>"$TRUFFLEHOG_LOG" | \
jq -R 'select(length > 0) | try fromjson catch empty | select(.Raw != null and .Raw != "") | {
DetectorName: .DetectorName,
file: .SourceMetadata.Data.Filesystem.file,
Raw: .Raw
}' | jq -s '.' > "$OUTPUT_FILE"; then
log_error "TruffleHog scan failed"
log_error "This could be due to:"
log_error " - Insufficient permissions to read files"
log_error " - Corrupted exclude patterns file"
log_error " - TruffleHog internal error"
if [ -f "$TRUFFLEHOG_LOG" ]; then
log_error "TruffleHog error details:"
cat "$TRUFFLEHOG_LOG" >&2
rm -f "$TRUFFLEHOG_LOG"
else
log_error "No error log available - check TruffleHog installation"
fi
exit 1
fi
# Clean up log file and mark cleanup as complete
rm -f "$TRUFFLEHOG_LOG"
CLEANUP_NEEDED=false
log_verbose "TruffleHog scan completed"
}
# Process and report scan results
# Validates JSON output, counts results, calculates execution time
# Provides summary statistics and file size information
process_results() {
log_verbose "Processing results..."
# Calculate execution time
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
MINUTES=$((DURATION / 60))
SECONDS=$((DURATION % 60))
# Count results with JSON validation
if [ -f "$OUTPUT_FILE" ]; then
# Validate JSON format first
if ! jq empty "$OUTPUT_FILE" 2>/dev/null; then
log_error "Output file contains invalid JSON format"
log_error "This may indicate a problem with the TruffleHog scan or JSON processing"
exit 1
fi
# Count results safely
RESULT_COUNT=$(jq 'length' "$OUTPUT_FILE" 2>/dev/null || echo "0")
FILE_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
if [ "$RESULT_COUNT" -gt 0 ]; then
log_warn "Found $RESULT_COUNT potential secrets in $MINUTES minutes and $SECONDS seconds"
log_warn "Results saved to: $OUTPUT_FILE ($FILE_SIZE)"
log_info "Review the results carefully and take appropriate action"
else
log_success "No secrets found in $MINUTES minutes and $SECONDS seconds"
log_success "Results saved to: $OUTPUT_FILE ($FILE_SIZE)"
fi
else
log_error "Output file was not created"
exit 1
fi
}
# Generate summary report from JSON output
# Creates a comprehensive summary with statistics, top detectors, and file analysis
generate_summary() {
log_verbose "Generating summary report..."
if [ ! -f "$OUTPUT_FILE" ] || [ ! -s "$OUTPUT_FILE" ]; then
log_warn "No output file available for summary generation"
return 0
fi
# Create summary file path
SUMMARY_FILE="${OUTPUT_FILE%.*}_summary.txt"
{
echo "=========================================="
echo "TRUFFLEHOG SECURITY SCAN SUMMARY"
echo "=========================================="
echo "Generated: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Scan Directory: $SCAN_DIR"
echo "Output File: $OUTPUT_FILE"
echo ""
# Basic statistics
TOTAL_FINDINGS=$(jq 'length' "$OUTPUT_FILE" 2>/dev/null || echo "0")
echo "TOTAL FINDINGS: $TOTAL_FINDINGS"
echo ""
if [ "$TOTAL_FINDINGS" -eq 0 ]; then
echo "✅ No secrets found - scan completed successfully!"
echo ""
echo "This indicates that no potential secrets were detected"
echo "in the scanned directory. However, please note that:"
echo "- This is a static analysis and may not catch all secrets"
echo "- Review the exclude patterns to ensure nothing important was skipped"
echo "- Consider running additional security scans"
else
echo "⚠️ SECRETS DETECTED - IMMEDIATE ACTION REQUIRED!"
echo ""
# Top detectors
echo "TOP DETECTORS:"
echo "--------------"
jq -r '.[].DetectorName' "$OUTPUT_FILE" 2>/dev/null | sort | uniq -c | sort -nr | head -10 | \
while read count detector; do
printf "%-4s %s\n" "$count" "$detector"
done
echo ""
# Files with most findings
echo "FILES WITH MOST FINDINGS:"
echo "------------------------"
jq -r '.[].file' "$OUTPUT_FILE" 2>/dev/null | sort | uniq -c | sort -nr | head -10 | \
while read count file; do
printf "%-4s %s\n" "$count" "$file"
done
echo ""
# File extensions analysis
echo "FILE EXTENSIONS ANALYSIS:"
echo "------------------------"
jq -r '.[].file' "$OUTPUT_FILE" 2>/dev/null | sed 's/.*\.//' | sort | uniq -c | sort -nr | head -10 | \
while read count ext; do
if [ -n "$ext" ] && [ "$ext" != "null" ]; then
printf "%-4s .%s\n" "$count" "$ext"
else
printf "%-4s (no extension)\n" "$count"
fi
done
echo ""
# Severity analysis (based on detector types)
echo "DETECTOR CATEGORIES:"
echo "-------------------"
jq -r '.[].DetectorName' "$OUTPUT_FILE" 2>/dev/null | \
while read detector; do
case "$detector" in
*"AWS"*|*"GCP"*|*"Azure"*) echo "Cloud Credentials" ;;
*"API"*|*"Token"*|*"Key"*) echo "API Keys & Tokens" ;;
*"Password"*|*"Secret"*) echo "Passwords & Secrets" ;;
*"Database"*|*"DB"*) echo "Database Credentials" ;;
*"SSH"*|*"RSA"*|*"Private"*) echo "SSH Keys" ;;
*"GitHub"*|*"GitLab"*|*"Bitbucket"*) echo "Git Credentials" ;;
*) echo "Other" ;;
esac
done | sort | uniq -c | sort -nr | \
while read count category; do
printf "%-4s %s\n" "$count" "$category"
done
echo ""
# Recommendations
echo "RECOMMENDATIONS:"
echo "----------------"
echo "1. IMMEDIATELY rotate/revoke any exposed credentials"
echo "2. Review and remove secrets from version control history"
echo "3. Implement pre-commit hooks to prevent future leaks"
echo "4. Use environment variables or secret management systems"
echo "5. Conduct security training for development team"
echo "6. Set up continuous monitoring for secret detection"
echo ""
# Sample findings (first 5)
echo "SAMPLE FINDINGS (first 5):"
echo "-------------------------"
jq -r '.[0:5] | .[] | "File: \(.file)\nDetector: \(.DetectorName)\nRaw: \(.Raw)\n"' "$OUTPUT_FILE" 2>/dev/null
fi
echo "=========================================="
echo "END OF SUMMARY"
echo "=========================================="
} > "$SUMMARY_FILE"
if [ -f "$SUMMARY_FILE" ]; then
SUMMARY_SIZE=$(du -h "$SUMMARY_FILE" | cut -f1)
log_success "Summary report generated: $SUMMARY_FILE ($SUMMARY_SIZE)"
if [ "$TOTAL_FINDINGS" -gt 0 ]; then
log_warn "Review the summary report for detailed analysis"
else
log_info "Summary report available for reference"
fi
else
log_error "Failed to generate summary report"
fi
}
# Main execution function
# Orchestrates the entire scan workflow from argument parsing to result processing
# Handles timing and provides comprehensive logging throughout the process
main() {
# Initialize timing
START_TIME=$(date +%s)
# Parse command line arguments
parse_arguments "$@"
# Check environment variables
check_environment
# Validate arguments
validate_arguments
# Show configuration
log_info "Starting TruffleHog security scan"
log_info "Scan directory: $SCAN_DIR"
log_info "Output file: $OUTPUT_FILE"
log_info "Exclude patterns file: $EXCLUDE_FILE"
log_verbose "Debug mode: $DEBUG"
log_verbose "Verbose mode: $VERBOSE"
log_verbose "Quiet mode: $QUIET"
log_verbose "Colors: $([ "$USE_COLORS" = true ] && echo "enabled" || echo "disabled")"
log_verbose "Verification: $([ "$NO_VERIFICATION" = true ] && echo "disabled" || echo "enabled")"
log_verbose "Summary: $([ "$GENERATE_SUMMARY" = true ] && echo "enabled" || echo "disabled")"
log_verbose "Log level: $LOG_LEVEL"
# Execute scan workflow
validate_inputs
check_dependencies
prepare_output
run_scan
process_results
# Generate summary if requested
if [ "$GENERATE_SUMMARY" = true ]; then
generate_summary
else
log_verbose "Summary generation skipped (--no-summary specified)"
fi
log_info "Scan completed successfully"
}
# Run main function with all arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment