From c47b02621b1cd83d752a8b287ca2e30221ab7da2 Mon Sep 17 00:00:00 2001 From: cschantz Date: Fri, 6 Mar 2026 22:11:23 -0500 Subject: [PATCH] CRITICAL FIX: Add timeout to chain_DENY ipset blocks (prevent permanent bans) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: When adding IPs to CSF's chain_DENY ipset, no timeout was specified Result: IPs were permanently blocked instead of 1-hour temporary ban Before: ipset add chain_DENY \"$ip\" -exist 2>/dev/null → Permanent block (until manually removed) After: ipset add chain_DENY \"$ip\" timeout 3600 -exist 2>/dev/null → Temporary 1-hour block (auto-removes) → Falls back to permanent if chain_DENY doesn't support timeouts Impact: - SYN attackers now get 1-hour temporary blocks, not permanent bans - Consistent with primary ipset blocking (also 3600s timeout) - Allows legitimate services to recover after attack ends - CSF -td fallback still manages timeout if needed Verification: - Tries timeout first (modern CSF/ipset) - Falls back to permanent if timeout not supported - Syntax validated Co-Authored-By: Claude Haiku 4.5 --- modules/security/live-attack-monitor-v2.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/security/live-attack-monitor-v2.sh b/modules/security/live-attack-monitor-v2.sh index f1612c7..176408d 100755 --- a/modules/security/live-attack-monitor-v2.sh +++ b/modules/security/live-attack-monitor-v2.sh @@ -984,8 +984,14 @@ batch_block_ips() { fi # Add directly to CSF's chain_DENY ipset (instant kernel-level blocking) - if ipset add chain_DENY "$ip" -exist 2>/dev/null; then - echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: chain_DENY ipset SUCCESS for $ip" >> "$TEMP_DIR/debug.log" 2>/dev/null || true + # Include 1-hour timeout if chain_DENY supports it + if ipset add chain_DENY "$ip" timeout 3600 -exist 2>/dev/null; then + echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: chain_DENY ipset SUCCESS for $ip (timeout 1h)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true + ((blocked++)) + echo "$ip" >> "$TEMP_DIR/blocked_ips_cache" + elif ipset add chain_DENY "$ip" -exist 2>/dev/null; then + # Fallback: chain_DENY doesn't support timeout (CSF will manage via csf -td in background) + echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: chain_DENY ipset SUCCESS for $ip (no timeout - CSF managed)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true ((blocked++)) echo "$ip" >> "$TEMP_DIR/blocked_ips_cache" else