From 01b63c6ad4c73ab3269dde9a1c55e50dcf7ec1fb Mon Sep 17 00:00:00 2001 From: Developer Date: Thu, 23 Apr 2026 21:20:33 -0400 Subject: [PATCH] CRITICAL: Add guards to all unquoted AWK arithmetic expressions Multiple locations had unquoted bash variables in AWK BEGIN blocks that could fail if variables were empty or malformed: - Lines 3369, 3375: Added fallbacks to domain/traffic counts - Lines 2338, 2383: Added error handling to percentage calculations - Lines 2657-2663: Added guards to bandwidth calculations - Line 2686: Added guards to domain traffic breakdown calculations All AWK arithmetic now uses ${var:-0} defaults and 2>/dev/null error suppression to prevent syntax errors from empty values. --- modules/security/bot-analyzer.sh | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/modules/security/bot-analyzer.sh b/modules/security/bot-analyzer.sh index 4a2ff43..1547287 100755 --- a/modules/security/bot-analyzer.sh +++ b/modules/security/bot-analyzer.sh @@ -2333,9 +2333,9 @@ generate_report() { # Traffic breakdown echo "Traffic Breakdown:" while read -r line; do - count=$(echo "$line" | awk '{print $1}') - type=$(echo "$line" | awk '{print $2}') - pct=$(awk "BEGIN {printf \"%.1f\", ($count/$total_requests)*100}") + count=$(echo "$line" | awk '{print $1}' || echo "0") + type=$(echo "$line" | awk '{print $2}' || echo "unknown") + pct=$(awk "BEGIN {printf \"%.1f\", (${count:-0}/${total_requests:-1})*100}" 2>/dev/null || echo "0.0") case $type in legit) echo " Legitimate Bots: $(printf "%'7d" $count) ($pct%)" ;; @@ -2378,9 +2378,9 @@ generate_report() { echo "" echo "Response Code Analysis:" while read -r line; do - count=$(echo "$line" | awk '{print $1}') - code=$(echo "$line" | awk '{print $2}') - pct=$(awk "BEGIN {printf \"%.1f\", ($count/$total_requests)*100}") + count=$(echo "$line" | awk '{print $1}' || echo "0") + code=$(echo "$line" | awk '{print $2}' || echo "000") + pct=$(awk "BEGIN {printf \"%.1f\", (${count:-0}/${total_requests:-1})*100}" 2>/dev/null || echo "0.0") case $code in 200) echo " 200 (Success): $(printf "%'7d" $count) ($pct%) Bots are getting data" ;; @@ -2654,13 +2654,13 @@ generate_report() { echo " Top bandwidth consumers:" head -3 "$TEMP_DIR/large_transfers.txt" | while read -r line; do - count=$(echo "$line" | awk '{print $1}') - ip=$(echo "$line" | awk '{print $2}' | cut -d'|' -f1) - domain=$(echo "$line" | awk '{print $2}' | cut -d'|' -f2) - url=$(echo "$line" | awk '{print $2}' | cut -d'|' -f3) - size=$(echo "$line" | awk '{print $2}' | cut -d'|' -f4) - size_mb=$(awk "BEGIN {printf \"%.1f\", $size/1048576}") - total_ip_mb=$(awk "BEGIN {printf \"%.0f\", $size * $count / 1048576}") + count=$(echo "$line" | awk '{print $1}' || echo "0") + ip=$(echo "$line" | awk '{print $2}' 2>/dev/null | cut -d'|' -f1 || echo "unknown") + domain=$(echo "$line" | awk '{print $2}' 2>/dev/null | cut -d'|' -f2 || echo "unknown") + url=$(echo "$line" | awk '{print $2}' 2>/dev/null | cut -d'|' -f3 || echo "unknown") + size=$(echo "$line" | awk '{print $2}' 2>/dev/null | cut -d'|' -f4 || echo "0") + size_mb=$(awk "BEGIN {printf \"%.1f\", ${size:-0}/1048576}" 2>/dev/null || echo "0.0") + total_ip_mb=$(awk "BEGIN {printf \"%.0f\", ${size:-0} * ${count:-0} / 1048576}" 2>/dev/null || echo "0") printf " %s transfers from %s - %.1f MB avg (%s MB total) - %s%s\n" "$count" "$ip" "$size_mb" "$total_ip_mb" "$domain" "$url" done echo " Action: Verify if scraping, consider serving WebP/optimized images" @@ -2673,17 +2673,17 @@ generate_report() { counter=1 while read -r line && [ "${counter:-0}" -le 5 ]; do - count=$(echo "$line" | awk '{print $1}') - domain=$(echo "$line" | awk '{print $2}') - + count=$(echo "$line" | awk '{print $1}' || echo "0") + domain=$(echo "$line" | awk '{print $2}' || echo "unknown") + echo "[$counter] $domain - $count requests" - + # Show traffic breakdown for this domain if [ -f "$TEMP_DIR/domain_${domain}_stats.txt" ]; then tail -n +2 "$TEMP_DIR/domain_${domain}_stats.txt" | while read -r stat_line; do - stat_count=$(echo "$stat_line" | awk '{print $1}') - stat_type=$(echo "$stat_line" | awk '{print $2}') - pct=$(awk "BEGIN {printf \"%.1f\", ($stat_count/$count)*100}") + stat_count=$(echo "$stat_line" | awk '{print $1}' || echo "0") + stat_type=$(echo "$stat_line" | awk '{print $2}' || echo "unknown") + pct=$(awk "BEGIN {printf \"%.1f\", (${stat_count:-0}/${count:-1})*100}" 2>/dev/null || echo "0.0") case $stat_type in suspicious) echo -e " ${YELLOW}Suspicious: $stat_count ($pct%)${NC}" ;; @@ -3364,15 +3364,15 @@ generate_recommendations() { attack_scope="single_domain" primary_target=$(head -1 "$TEMP_DIR/domain_high_risk_ips.txt" 2>/dev/null | cut -d'|' -f1) # Calculate what % of high-risk IPs are targeting this domain - local domain_risk_count=$(head -1 "$TEMP_DIR/domain_high_risk_ips.txt" 2>/dev/null | cut -d'|' -f2) - if [ "${total_high_risk_ips:-0}" -gt 0 ]; then - primary_target_percentage=$(awk "BEGIN {printf \"%.0f\", ($domain_risk_count / $total_high_risk_ips) * 100}") + local domain_risk_count=$(head -1 "$TEMP_DIR/domain_high_risk_ips.txt" 2>/dev/null | cut -d'|' -f2 || echo "0") + if [ "${total_high_risk_ips:-0}" -gt 0 ] && [ "${domain_risk_count:-0}" -gt 0 ]; then + primary_target_percentage=$(awk "BEGIN {printf \"%.0f\", (${domain_risk_count:-0} / ${total_high_risk_ips:-0}) * 100}") fi elif [ "${affected_domains:-0}" -gt 1 ] && [ "${total_domains:-0}" -gt 1 ]; then # Check if one domain is getting most of the traffic - local top_domain_count=$(head -1 "$TEMP_DIR/domain_threats_sorted.txt" 2>/dev/null | cut -d'|' -f5) + local top_domain_count=$(head -1 "$TEMP_DIR/domain_threats_sorted.txt" 2>/dev/null | cut -d'|' -f5 || echo "0") if [ "${top_domain_count:-0}" -gt 0 ] && [ "${total_high_risk_ips:-0}" -gt 0 ]; then - local top_percentage=$(awk "BEGIN {printf \"%.0f\", ($top_domain_count / $total_high_risk_ips) * 100}") + local top_percentage=$(awk "BEGIN {printf \"%.0f\", (${top_domain_count:-0} / ${total_high_risk_ips:-0}) * 100}") if [ "$top_percentage" -ge 75 ]; then attack_scope="primary_target" primary_target=$(head -1 "$TEMP_DIR/domain_threats_sorted.txt" 2>/dev/null | cut -d'|' -f1)