Auto-banned IPs not taking effect until node restarted

Issue Description

IPs blocked via the Auto banning port scanner are not taking effect without a manual node reboot. Action → Reload → Blocked IPs list has no effect.

Expected Behavior

When a blocked IP address is added to the list due to a security scan, it should immediately take effect without further intervention.

Actual Behavior

The IP continues to scan and the log file continues to report banning it as if it was a new event.

Reproduction Steps

  1. Wait for a scanner to start scanning a node
  2. Observe the log entry to confirm the IP has been blocked
  3. Check the block list, confirm the IP is there
  4. Actions → Reload → Blocked IPs list - does not have an effect as the log entries continue
  5. Restart the node, the port scanning log entries stop, assuming they are now in effect

Relevant Log Output

Truncated to last 3 entries for each IP

2026-05-27T06:10:37Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 150.109.104.66, remotePort = 52418, remoteIp = 150.109.104.66, path = "/demo/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"
2026-05-27T06:10:42Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 150.109.104.66, remotePort = 52418, remoteIp = 150.109.104.66, path = "/cms/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"
2026-05-27T06:10:46Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 150.109.104.66, remotePort = 52418, remoteIp = 150.109.104.66, path = "/crm/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"
2026-05-27T10:18:52Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 195.178.110.199, remotePort = 38166, remoteIp = 195.178.110.199, path = "/wp-json/gravitysmtp/v1/tests/mock-data"
2026-05-27T10:18:52Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 195.178.110.199, remotePort = 38236, remoteIp = 195.178.110.199, path = "/wp-content/mysql.sql"
2026-05-27T10:18:52Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 195.178.110.199, remotePort = 38218, remoteIp = 195.178.110.199, path = "/wp-json/wp/v2/users"
2026-05-27T17:25:58Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 101.47.8.187, remotePort = 58518, remoteIp = 101.47.8.187, path = "/apps/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"
2026-05-27T17:25:59Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 101.47.8.187, remotePort = 58518, remoteIp = 101.47.8.187, path = "/app/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"
2026-05-27T17:26:00Z INFO Banned due to scan (security.scan-ban) listenerId = "https", localPort = 443, remoteIp = 101.47.8.187, remotePort = 58518, remoteIp = 101.47.8.187, path = "/public/index.php"

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

PostgreSQL

Blob Storage

S3-compatible

Search Engine

Internal

Directory Backend

Internal

Additional Context

The documentation states that this action should be immediately in effect

Auto-banning | Stalwart states:

If an IP address attempts to scan these ports and the number of attempts exceeds a pre-configured threshold, Stalwart will automatically block the offending IP address. This immediate response prevents attackers from continuing their scan and reduces the risk of further exploitation.

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

This probably happened because the attacker connected over HTTP with Keep-Alive enabled and reused the same connection for the scans. This gap has now been fixed. The fix will be included in v0.16.7.