#!/bin/bash # # DSS - Secret Scanner # Non-destructive scan for potential exposed secrets # Outputs JSON with risk report (no actual secret values) # set -e PROJECT_PATH="${1:-.}" # Patterns to detect (regex) SECRET_PATTERNS=( "password\s*[:=]\s*['\"][^'\"]+['\"]" "api[_-]?key\s*[:=]\s*['\"][^'\"]+['\"]" "secret[_-]?key\s*[:=]\s*['\"][^'\"]+['\"]" "access[_-]?token\s*[:=]\s*['\"][^'\"]+['\"]" "private[_-]?key\s*[:=]\s*['\"][^'\"]+['\"]" "aws[_-]?access" "AKIA[0-9A-Z]{16}" "ghp_[a-zA-Z0-9]{36}" "sk-[a-zA-Z0-9]{48}" ) # Files to ignore IGNORE_DIRS="node_modules|\.git|dist|build|__pycache__|\.next|venv" # Initialize results declare -a findings scan_for_secrets() { local pattern="$1" local results results=$(grep -rEil "$pattern" "$PROJECT_PATH" \ --include="*.js" --include="*.ts" --include="*.py" \ --include="*.json" --include="*.yaml" --include="*.yml" \ --include="*.env*" --include="*.config.*" \ 2>/dev/null | grep -vE "$IGNORE_DIRS" | head -20 || true) if [[ -n "$results" ]]; then while IFS= read -r file; do if [[ -n "$file" ]]; then # Get line count without revealing content local count=$(grep -cEi "$pattern" "$file" 2>/dev/null || echo 0) findings+=("{\"file\":\"${file#$PROJECT_PATH/}\",\"pattern\":\"${pattern:0:30}...\",\"matches\":$count}") fi done <<< "$results" fi } # Check for common secret files check_secret_files() { local risky_files=( ".env" ".env.local" ".env.production" "credentials.json" "secrets.json" "config/secrets.yml" ".aws/credentials" "id_rsa" "id_ed25519" "*.pem" "*.key" ) for pattern in "${risky_files[@]}"; do local found=$(find "$PROJECT_PATH" -name "$pattern" -type f ! -path "*/$IGNORE_DIRS/*" 2>/dev/null | head -5) if [[ -n "$found" ]]; then while IFS= read -r file; do if [[ -n "$file" ]]; then # Check if file is in .gitignore local in_gitignore="false" if [[ -f "$PROJECT_PATH/.gitignore" ]]; then grep -q "$(basename "$file")" "$PROJECT_PATH/.gitignore" 2>/dev/null && in_gitignore="true" fi findings+=("{\"file\":\"${file#$PROJECT_PATH/}\",\"type\":\"risky_file\",\"in_gitignore\":$in_gitignore}") fi done <<< "$found" fi done } # Run scans for pattern in "${SECRET_PATTERNS[@]}"; do scan_for_secrets "$pattern" done check_secret_files # Calculate risk score total_findings=${#findings[@]} risk_score="low" [[ $total_findings -gt 5 ]] && risk_score="medium" [[ $total_findings -gt 15 ]] && risk_score="high" [[ $total_findings -gt 30 ]] && risk_score="critical" # Output JSON joined=$(IFS=,; echo "${findings[*]}") cat <