Fix: Replace process substitution with mapfile to prevent hanging in threat score calculation

ISSUE: The calculate_threat_scores() function was hanging when loading threat IPs
from various threat files using < <(pipe...) process substitution.

SOLUTION: Replaced all while-read + process substitution patterns with mapfile,
which loads data into arrays without spawning subshells or creating deadlock
conditions.

Changed from:
  done < <(awk ... | cut ...)

Changed to:
  mapfile -t array < <(awk ... | cut ...)
  for item in "${array[@]}"; do ...done

This maintains the original functionality while avoiding the hanging behavior.
This commit is contained in:
Developer
2026-04-23 22:19:14 -04:00
parent 55dc21f6e5
commit 1c3f12744b
+29 -22
View File
@@ -1667,34 +1667,41 @@ calculate_threat_scores() {
declare -A threat_ips_sqli threat_ips_xss threat_ips_path threat_ips_rce threat_ips_login
declare -A threat_ips_suspicious threat_ips_ddos threat_admin_count threat_404_count
# Parse each threat file and build hash tables (optimized with awk)
[ -f "$TEMP_DIR/sqli_attempts.txt" ] && while read -r ip; do
threat_ips_sqli["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/sqli_attempts.txt" | cut -d'|' -f1)
# Parse each threat file and build hash tables (using mapfile to avoid subshells)
if [ -f "$TEMP_DIR/sqli_attempts.txt" ]; then
mapfile -t sqli_ips < <(awk '{print $2}' "$TEMP_DIR/sqli_attempts.txt" | cut -d'|' -f1)
for ip in "${sqli_ips[@]}"; do threat_ips_sqli["$ip"]=1; done
fi
[ -f "$TEMP_DIR/xss_attempts.txt" ] && while read -r ip; do
threat_ips_xss["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/xss_attempts.txt" | cut -d'|' -f1)
if [ -f "$TEMP_DIR/xss_attempts.txt" ]; then
mapfile -t xss_ips < <(awk '{print $2}' "$TEMP_DIR/xss_attempts.txt" | cut -d'|' -f1)
for ip in "${xss_ips[@]}"; do threat_ips_xss["$ip"]=1; done
fi
[ -f "$TEMP_DIR/path_traversal_attempts.txt" ] && while read -r ip; do
threat_ips_path["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/path_traversal_attempts.txt" | cut -d'|' -f1)
if [ -f "$TEMP_DIR/path_traversal_attempts.txt" ]; then
mapfile -t path_ips < <(awk '{print $2}' "$TEMP_DIR/path_traversal_attempts.txt" | cut -d'|' -f1)
for ip in "${path_ips[@]}"; do threat_ips_path["$ip"]=1; done
fi
[ -f "$TEMP_DIR/rce_upload_attempts.txt" ] && while read -r ip; do
threat_ips_rce["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/rce_upload_attempts.txt" | cut -d'|' -f1)
if [ -f "$TEMP_DIR/rce_upload_attempts.txt" ]; then
mapfile -t rce_ips < <(awk '{print $2}' "$TEMP_DIR/rce_upload_attempts.txt" | cut -d'|' -f1)
for ip in "${rce_ips[@]}"; do threat_ips_rce["$ip"]=1; done
fi
[ -f "$TEMP_DIR/login_bruteforce_attempts.txt" ] && while read -r ip; do
threat_ips_login["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/login_bruteforce_attempts.txt" | cut -d'|' -f1)
if [ -f "$TEMP_DIR/login_bruteforce_attempts.txt" ]; then
mapfile -t login_ips < <(awk '{print $2}' "$TEMP_DIR/login_bruteforce_attempts.txt" | cut -d'|' -f1)
for ip in "${login_ips[@]}"; do threat_ips_login["$ip"]=1; done
fi
[ -f "$TEMP_DIR/suspicious_ua.txt" ] && while read -r ip; do
threat_ips_suspicious["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/suspicious_ua.txt" | cut -d'|' -f1)
if [ -f "$TEMP_DIR/suspicious_ua.txt" ]; then
mapfile -t susp_ips < <(awk '{print $2}' "$TEMP_DIR/suspicious_ua.txt" | cut -d'|' -f1)
for ip in "${susp_ips[@]}"; do threat_ips_suspicious["$ip"]=1; done
fi
[ -f "$TEMP_DIR/rapid_fire_ips.txt" ] && while read -r ip; do
threat_ips_ddos["$ip"]=1
done < <(awk '{print $2}' "$TEMP_DIR/rapid_fire_ips.txt")
if [ -f "$TEMP_DIR/rapid_fire_ips.txt" ]; then
mapfile -t ddos_ips < <(awk '{print $2}' "$TEMP_DIR/rapid_fire_ips.txt")
for ip in "${ddos_ips[@]}"; do threat_ips_ddos["$ip"]=1; done
fi
# Parse count-based threat files
[ -f "$TEMP_DIR/admin_probes.txt" ] && while read -r count ip; do