You wake up to a mailbox full of “Login attempt blocked” alerts, your CPU fan is auditioning for a jet engine,
and users are asking why their phone email “just spins.” Meanwhile, your mail logs look like a slot machine:
connect, auth fail, connect, auth fail—thousands per minute.
Brute force and password spraying on IMAP/SMTP are boring attacks with exciting consequences. The fix is not “turn it off”
or “block the internet.” The fix is layered controls that slow attackers down, surface the real problem fast, and keep
you—from the admin desk to the on-call phone—from accidentally locking out the only people who can fix it.
Know what you’re fighting: brute force vs spraying vs credential stuffing
Brute force
Classic brute force is repeated guesses against one account (or a small set) until something sticks. On IMAP/SMTP,
it often targets common usernames like admin, info, sales, plus any real addresses
scraped from your website. These attacks are noisy: lots of failures, often from a small number of IPs, sometimes
from botnets rotating through cheap VPS ranges.
Password spraying
Spraying is the “subtle” cousin: try one or a few common passwords across many accounts. It avoids account lockouts
and looks less like a meltdown, more like background radiation—until it hits a reused password and becomes your incident.
Spraying is especially common on IMAP because it’s widely exposed and the feedback loop is fast.
Credential stuffing
Stuffing is when attackers use breached username/password pairs from other sites. The mail server is just the destination;
the breach happened elsewhere. The attack tends to have a higher success rate than brute force. The log patterns can look
“valid”: one try per account, sometimes successful, then immediate activity from the mailbox or SMTP AUTH sending.
Why IMAP/SMTP are such tempting targets
Email is still the skeleton key in corporate life: password resets, vendor invoices, HR documents, and “please wire money now”
conversations all live there. A compromised mailbox often becomes an internal pivot and a fraud platform, not just a privacy problem.
Also: many mail stacks are old, heavily customized, and treated like “appliances” until they’re on fire.
One practical rule: don’t treat “brute force on IMAP/SMTP” as a perimeter-only problem. It’s an authentication problem, a monitoring
problem, and a change-management problem. You can block a thousand IPs and still lose to one reused password.
Joke #1: Attackers love IMAP because it’s always there—like that one printer in accounting that refuses to retire.
A few facts and historical context (because mail never dies)
- SMTP predates the modern internet. SMTP was standardized in the early 1980s and assumed a friendlier network. “Hostile authentication at scale” wasn’t in the design brief.
- IMAP is older than most “cloud first” strategies. IMAP emerged in the 1980s too, optimized for remote mailbox access long before smartphones made it everyone’s problem.
- Port 25 wasn’t meant for user login. SMTP on 25 is for server-to-server transport; authenticated submission moved to 587 to separate concerns and policy.
- “Less secure apps” created a long tail of weak auth. For years, clients logged in with plain passwords to fetch mail; modern MFA and app passwords arrived late and unevenly.
- Password spraying rose with lockout policies. Once enterprises started locking accounts after N failures, attackers adapted to low-and-slow patterns across many users.
- Botnets made brute force cheap. Distributed attempts from thousands of IPs turn per-IP blocking into whack-a-mole unless you rate-limit and harden auth.
- Mail logs are unusually rich. Postfix/Dovecot can tell you who tried, from where, and how often—if you store logs long enough and don’t drown them in noise.
- “TLS everywhere” helped, but not against guessing. Encrypting the channel prevents sniffing; it does nothing against an attacker who already has lists of passwords.
Fast diagnosis playbook (first/second/third checks)
When you’re under active attack, your job is to (1) keep mail flowing for legitimate users, (2) stop the bleeding,
and (3) preserve enough evidence to learn something. Here’s the order that keeps you honest.
First: confirm what’s failing and where
- Are users failing to authenticate or failing to connect? Authentication failures look like
auth failed; connection failures look like timeouts/refused. - Is it IMAP, submission (587), SMTPS (465), or something else? Don’t “fix SMTP” if it’s IMAP, and don’t block 587 if your users rely on it.
- Is the box CPU-bound, I/O-bound, or connection-table bound? Under brute force, you can saturate CPU (TLS + auth), I/O (logs + auth backends), or network conntrack.
Second: identify the dominant attack pattern
- Few IPs hammering? Per-IP bans and firewall rate limits work well.
- Many IPs, many users, low rate? That’s spraying/stuffing. You need per-user throttling, stronger auth, and anomaly detection.
- Are successes happening? If yes, you’re in compromise territory: disable accounts, reset credentials, check outbound mail, and review MFA/app passwords.
Third: apply the minimum-change mitigation
- Turn on or tighten existing throttles (Dovecot auth penalties, Postfix SASL rate limits, fail2ban) before deploying new tooling mid-incident.
- Whitelist your admin lifeline (VPN egress, bastion, office IP) before aggressive blocking. You want a controlled door you can still open.
- Don’t “restart until it works.” Restarts can clear logs, rotate IP tables state, and give you a false sense of progress while the attack resumes immediately.
“Hope is not a strategy” is commonly attributed in ops circles, but the paraphrased idea fits: plan the failure modes before they become your ticket queue.
One quote worth keeping in your head: Paraphrased idea: “Systems fail in complex ways; reliability comes from preparing and learning, not from pretending failures won’t happen.”
— Richard Cook (paraphrased idea)
Practical tasks: commands, outputs, and the decision you make
These are not “run this magic incantation.” They are the exact drills I want on a runbook: command, sample output,
what it means, and what you do next. Adjust paths and service names for your distro, but keep the logic.
Task 1: Confirm which ports are exposed (and by what)
cr0x@server:~$ sudo ss -lntp | egrep ':(25|110|143|465|587|993|995)\s'
LISTEN 0 100 0.0.0.0:25 0.0.0.0:* users:(("master",pid=1123,fd=13))
LISTEN 0 100 0.0.0.0:587 0.0.0.0:* users:(("master",pid=1123,fd=15))
LISTEN 0 100 0.0.0.0:465 0.0.0.0:* users:(("master",pid=1123,fd=16))
LISTEN 0 128 0.0.0.0:993 0.0.0.0:* users:(("dovecot",pid=998,fd=41))
LISTEN 0 128 0.0.0.0:143 0.0.0.0:* users:(("dovecot",pid=998,fd=40))
What it means: Services are listening on public interfaces for SMTP (25), submission (587/465), and IMAP (143/993).
Decision: If you don’t need plaintext IMAP (143) on the internet, stop exposing it. If 465 exists but isn’t used, consider disabling it to shrink the surface.
Task 2: Check current connection pressure (are you getting flooded?)
cr0x@server:~$ sudo ss -ant state established '( sport = :993 or sport = :587 )' | wc -l
842
What it means: 842 established connections on IMAPS/submission. That might be normal for a big org, or catastrophic for a small one.
Decision: Compare with baseline. If it’s 10x normal, move to attacker IP breakdown and rate limiting.
Task 3: Find top source IPs hitting IMAPS right now
cr0x@server:~$ sudo ss -ant '( dport = :993 )' | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head
210 203.0.113.77
198 198.51.100.22
95 192.0.2.14
41 203.0.113.19
What it means: A few IPs dominate. This is the easy mode for blocking.
Decision: If these are not your NAT egresses or known monitoring, block or rate-limit them at the firewall. If it’s “many IPs with low counts,” shift to per-user controls.
Task 4: Count authentication failures in the last 10 minutes (Dovecot)
cr0x@server:~$ sudo journalctl -u dovecot --since "10 min ago" | egrep -i 'auth failed|authentication failure' | wc -l
12458
What it means: This is active and intense. At this rate, you’ll burn CPU, logs, and possibly your auth backend.
Decision: Enable throttling immediately (Dovecot auth penalties) and verify fail2ban is actually banning.
Task 5: Extract top attacked usernames (spraying vs brute force clue)
cr0x@server:~$ sudo journalctl -u dovecot --since "30 min ago" | egrep -o 'user=<[^>]+' | cut -d'<' -f2 | sort | uniq -c | sort -nr | head
611 user=info@example.com
588 user=admin@example.com
512 user=support@example.com
498 user=sales@example.com
What it means: High counts on a few mailboxes points to brute force. If you saw hundreds of different users with small counts, that’s spraying.
Decision: For high-value shared mailboxes (info@, support@), enforce MFA/app passwords or disable IMAP access entirely if possible.
Task 6: Confirm fail2ban is running and has a Dovecot jail
cr0x@server:~$ sudo fail2ban-client status
Status
|- Number of jail: 3
`- Jail list: dovecot, postfix-sasl, sshd
What it means: You have relevant jails. Good. Now see if they’re effective.
Decision: If there’s no dovecot or postfix-sasl jail, you’re relying on luck and log volume.
Task 7: Check how many IPs are currently banned and whether bans are increasing
cr0x@server:~$ sudo fail2ban-client status dovecot
Status for the jail: dovecot
|- Filter
| |- Currently failed: 128
| |- Total failed: 54122
| `- File list: /var/log/mail.log
`- Actions
|- Currently banned: 317
|- Total banned: 2901
`- Banned IP list: 203.0.113.77 198.51.100.22 192.0.2.14
What it means: Bans are happening. The “currently failed” number tells you the jail is still seeing attempts.
Decision: If Currently banned is near zero during an obvious attack, your filter regex is wrong, your log path is wrong, or you’re logging to journald only.
Task 8: Verify your mail logs are actually being written where you think
cr0x@server:~$ sudo ls -lh /var/log/mail.log
-rw-r----- 1 syslog adm 1.8G Jan 4 01:11 /var/log/mail.log
What it means: Log file exists and is large. Under attack, log I/O can become a bottleneck.
Decision: If the log is exploding and you’re I/O bound, consider temporary rate limiting and ensure logrotate is sane. Don’t disable logging mid-incident unless you’re already out of disk.
Task 9: Check disk space (because “mail down” can be “disk full” wearing a costume)
cr0x@server:~$ df -h /var /var/log
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 100G 96G 4.0G 97% /var
/dev/sda2 100G 96G 4.0G 97% /var/log
What it means: You are 3% away from a self-inflicted outage. Under brute force, logs can push you over.
Decision: Free space safely (rotate/compress, archive), then reduce log amplification by stopping repeated auth attempts (throttles/bans).
Task 10: Confirm Postfix sees SASL auth failures on submission
cr0x@server:~$ sudo journalctl -u postfix --since "15 min ago" | egrep -i 'SASL.*authentication failed|warning: SASL' | head
Jan 04 01:02:11 mx1 postfix/smtpd[22103]: warning: unknown[203.0.113.77]: SASL LOGIN authentication failed: authentication failure
Jan 04 01:02:12 mx1 postfix/smtpd[22105]: warning: unknown[203.0.113.77]: SASL PLAIN authentication failed: authentication failure
What it means: Attack is also on SMTP AUTH. That’s common: attackers try both IMAP and submission.
Decision: Ensure your postfix-sasl fail2ban jail matches these lines, and apply rate limits on smtpd if needed.
Task 11: Inspect nftables/iptables counters for mail ports
cr0x@server:~$ sudo nft list ruleset | egrep -n 'dport (25|587|465|993|143)'
42: tcp dport { 25, 587, 465, 993 } ct state new accept
What it means: You accept new connections without any rate limiting. Under attack, that can overwhelm processes and conntrack.
Decision: Add rate limiting for new connections to IMAP/SMTP AUTH ports, with careful thresholds and whitelisting.
Task 12: Check conntrack utilization (silent killer during floods)
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 247812
net.netfilter.nf_conntrack_max = 262144
What it means: You’re near conntrack max. When you hit it, legitimate connections start failing in weird ways.
Decision: Rate-limit new connections, consider increasing conntrack max (with memory awareness), and drop obviously abusive sources earlier.
Task 13: Identify whether you’re CPU-bound in TLS/auth
cr0x@server:~$ top -b -n 1 | head -20
top - 01:04:33 up 21 days, 2:11, 1 user, load average: 18.42, 17.90, 14.20
%Cpu(s): 86.5 us, 9.2 sy, 0.0 ni, 1.1 id, 0.0 wa, 0.0 hi, 3.2 si, 0.0 st
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
998 dovecot 20 0 786972 41280 12624 R 215.0 0.5 52:10.11 dovecot/auth
1123 root 20 0 145772 12204 8560 S 85.0 0.1 31:02.24 master
What it means: Dovecot auth is chewing CPU. Could be bcrypt/sha512-crypt verification under attack (expected), could be LDAP latency causing retries (worse).
Decision: Add auth throttling and check auth backend health. Don’t “optimize” hashes downward; that’s how you trade security for a temporary quiet.
Task 14: Check if your auth backend (LDAP) is the real bottleneck
cr0x@server:~$ sudo journalctl -u dovecot --since "10 min ago" | egrep -i 'ldap|connect\(\) failed|timed out' | tail -5
Jan 04 01:00:17 mx1 dovecot: auth: Error: ldap(example.com): Connection timed out
Jan 04 01:00:21 mx1 dovecot: auth: Error: ldap(example.com): Unable to connect to server: Can't contact LDAP server
What it means: The attack is now an auth-backend DoS. Even legitimate logins may fail because LDAP is saturated or unreachable.
Decision: Put aggressive throttles in front of LDAP (Dovecot auth policy, fail2ban), and consider caching or local auth for critical accounts.
Task 15: Confirm you’re not accidentally allowing plaintext logins
cr0x@server:~$ sudo dovecot -n | egrep -i 'disable_plaintext_auth|auth_mechanisms|ssl'
disable_plaintext_auth = yes
auth_mechanisms = plain login
ssl = required
What it means: TLS is required, plaintext auth is disabled, but you still allow PLAIN/LOGIN over TLS (fine). If ssl = yes and disable_plaintext_auth = no, you have risk.
Decision: Keep TLS required. If legacy clients demand non-TLS, fix the clients; don’t downgrade the server.
Task 16: Verify Postfix submission service restrictions (prevent abuse after compromise)
cr0x@server:~$ sudo postconf -n | egrep -i 'smtpd_tls_auth_only|smtpd_recipient_restrictions|smtpd_client_message_rate_limit'
smtpd_tls_auth_only = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,reject_unauth_destination
smtpd_client_message_rate_limit = 200
What it means: TLS-only auth is enabled, unauthenticated relay is blocked, and there’s a message rate limit per client.
Decision: If there’s no message rate limit, a single compromised account can send a lot before you notice. Add reasonable throttles and alert on spikes.
Layered controls that work in production
1) Shrink the exposed surface area (without breaking clients)
Every open port is a contract with the internet. Keep the contracts you need; terminate the ones you don’t.
Most orgs can do all of this:
- Expose IMAPS (993) and submission (587). Consider disabling IMAP plaintext (143) on public interfaces.
- Keep port 25 for server-to-server SMTP, but don’t allow user auth there. Users should authenticate on 587 (or 465 if you must).
- If you publish autodiscover/autoconfig, ensure it points to the secure ports only.
The more protocols you expose, the more policy you need to keep consistent. In practice, “consistent policy” is where incidents live.
2) Rate-limit new connections at the network edge
This is the fastest lever when you’re under load. Rate limiting buys time and protects conntrack and process tables.
It does not solve spraying, but it stops hammering.
Put limits on new connections to 993 and 587, per source IP. Be conservative: you’re shaping the internet, not punishing it.
Also: whitelist your VPN egress and monitoring probes.
3) Use fail2ban, but treat it like code
fail2ban is effective when:
- Your logs are in the place fail2ban reads.
- The regex matches your exact log format.
- Bantime/findtime/maxretry match the attacker pattern.
- You don’t ban your own NAT or your own security scanner.
Under spraying, maxretry can be irrelevant: attackers may do one attempt per IP. That’s why per-user throttling matters.
4) Throttle authentication per user, not just per IP
Per-IP controls fail against botnets. Per-user controls fail against distributed username guessing if you don’t have good user enumeration protection.
Still, per-user throttles are the difference between “attack noise” and “LDAP on fire.”
With Dovecot, you can introduce auth penalties and limit auth request concurrency. The goal is not to stop every attempt; the goal is to make the attack expensive
while keeping real users functional.
5) Harden authentication: MFA where possible, app passwords where you must
If you can do MFA for IMAP/SMTP, do it. In practice, many “traditional” IMAP/SMTP clients can’t handle interactive MFA,
so you’ll use application-specific passwords or OAuth-based mechanisms depending on your ecosystem.
If your environment is self-hosted and not integrated with an identity provider that supports modern auth, the pragmatic move is:
- Strong password policy, enforced server-side (length and common-password rejection).
- Disable login for shared mailboxes where feasible; use delegation instead.
- Require TLS, disable legacy auth where possible.
6) Detect compromise by watching what happens after auth succeeds
Successful logins during an attack are the real emergency. Your monitoring should flag:
- First-time IPs for a user, especially from unusual geographies.
- Sudden spikes in SMTP AUTH sends from a mailbox that usually only receives.
- IMAP login success followed by immediate large fetches (exfil patterns vary, but volume spikes are telling).
7) Keep admins safe: build an “always works” access path
Lockdown work is where teams lock themselves out. The fix is not bravery; it’s design:
- Have a VPN with stable egress IPs and whitelist them for management and (optionally) mail ports.
- Keep an out-of-band console path (cloud serial console, iDRAC/iLO) tested monthly.
- Store recovery procedures somewhere accessible when the mail server is down. If your runbook lives in email, you deserve the evening you’re about to have.
Joke #2: The easiest way to prove you have no out-of-band access is to block your own IP and then “SSH harder.”
Three corporate mini-stories from the trenches
Incident #1: The wrong assumption that took down “only IMAP”
A mid-sized company ran a classic Postfix + Dovecot stack. IMAP brute force started ramping up overnight.
On-call saw the obvious: thousands of failures per minute. The assumption: “It’s just IMAP, SMTP will be fine.”
They blocked a handful of IPs and went back to trying to sleep.
By morning, executives couldn’t send mail. The issue wasn’t SMTP. It was authentication.
Dovecot was configured to query LDAP for every auth attempt, and the brute force was effectively a sustained LDAP load test.
LDAP latency rose, auth requests piled up, and the same LDAP service also backed SMTP AUTH (submission). So submission started timing out too.
The team’s second assumption was worse: “If we restart Dovecot and Postfix, it’ll clear the queue.” It cleared some local state,
but the attackers kept coming. The restart also caused a brief storm of legitimate reconnects from mobile clients.
That legitimate reconnect burst plus the attack pushed LDAP over the edge.
The fix was not heroic. They applied Dovecot auth throttling and a firewall rate limit for new IMAPS connections,
then tuned fail2ban to ban faster for repeat failures. LDAP recovered within minutes.
Once stable, they reviewed which accounts were being targeted, forced password resets on a few shared mailboxes, and introduced app passwords.
The lesson: don’t isolate protocols mentally when they share the same auth backend. Under attack, everything that touches auth becomes one system.
Incident #2: The optimization that backfired (a little too clever with bans)
Another org decided fail2ban was “too slow” because it waited for log entries and then called a firewall action.
An engineer implemented an aggressive firewall rule that dropped new connections to IMAPS if a source IP opened more than a few connections per second.
It was fast and elegant. It also assumed the world looked like the engineer’s laptop.
The company had remote workers behind a few large consumer ISPs and a corporate VPN concentrator.
When a hundred users reconnected after a Wi‑Fi flap, they appeared as a small number of source IPs (NAT and VPN egress).
The new rule interpreted “hundreds of legitimate users” as “one very enthusiastic attacker.”
IMAP became flaky exactly when people needed it most.
Worse: the rate-limit drop had no logging. The helpdesk reported “mail is down,” metrics looked normal, and the mail server itself
showed no errors. The firewall was silently doing its job—against the wrong target.
They recovered by adding explicit whitelists for VPN egress and office NAT ranges, switching from “connections per second”
to “auth failures per unit time” where possible, and adding logging on the drop rule with careful sampling.
They also documented client behavior: mobile IMAP clients can open multiple parallel connections and reconnect aggressively.
The lesson: optimizations at the network edge need empathy for client behavior, not just contempt for attackers.
And silent drops are great until you need to debug reality at 03:00.
Incident #3: The boring practice that saved the day (baseline + safe whitelist)
A financial services team had a boring habit: every quarter, they recorded “normal” ranges for IMAP connections, auth failures,
and submission throughput. They also maintained a small, reviewed whitelist: their VPN egress IPs, their monitoring system,
and a break-glass bastion range. Nobody bragged about it. It never made a slide deck.
When brute force hit, the on-call compared live stats to baseline and immediately saw the difference: auth failures were 50x normal,
but successful logins were flat. That suggested brute force rather than a compromised account sending spam.
They activated a pre-approved incident change: tighten Dovecot penalties and reduce the allowed new connection rate to IMAPS.
The key detail: the whitelist was already in place and tested. Admin access continued. Monitoring stayed up.
They could iterate on bans without fear of losing control of the box.
After the attack, they reviewed targeted accounts and implemented a policy: shared mailboxes must not be used for login, only delegation.
Password resets were scoped, not panic-driven. Nobody got locked out of their own runbook, because the runbook lived outside email.
The lesson: boring baselines and boring whitelists are how you turn a security event into a routine ops day.
Common mistakes: symptoms → root cause → fix
1) Symptom: IMAP works for some users, fails randomly for others
Root cause: Per-IP rate limiting or fail2ban is banning NAT/VPN egress IPs. Many users share one source IP.
Fix: Whitelist VPN/office egress IPs. Prefer per-user throttling for auth failures. Add logging/sampling on firewall drops to see what you’re blocking.
2) Symptom: Mail server load is high, but network traffic isn’t crazy
Root cause: CPU is burning on TLS handshakes and password hash verification; attackers don’t need huge bandwidth.
Fix: Rate-limit new connections, enable auth penalties, and ensure TLS session reuse is configured appropriately. Keep password hashing strong; throttle attempts instead.
3) Symptom: “Authentication failed” spikes, then LDAP/AD alerts fire
Root cause: Auth backend is the choke point; brute force becomes an authentication DoS.
Fix: Put throttles at the mail server, consider caching where appropriate, and ensure the directory has sane connection limits and monitoring.
4) Symptom: fail2ban shows zero bans during an obvious attack
Root cause: Wrong log path, journald vs file mismatch, or regex filter doesn’t match your Dovecot/Postfix log format.
Fix: Validate log input. Run fail2ban-regex against your actual log lines. Confirm the jail references the real file(s).
5) Symptom: Disk fills overnight, then services start failing
Root cause: Log amplification under attack + weak logrotate + small /var. Sometimes combined with verbose auth debugging left on.
Fix: Fix logrotate, compress aggressively, store logs on a separate filesystem if you can, and stop the auth flood with throttling/bans.
6) Symptom: Outbound spam complaints, blacklisting, and angry customers
Root cause: Successful credential stuffing or weak passwords on SMTP AUTH. Attackers use your server as a relay by authenticating legitimately.
Fix: Reset credentials for affected accounts, enable MFA/app passwords where possible, add per-user send rate limits, and alert on anomalous sending patterns.
7) Symptom: You block “the attackers,” but the attack continues unchanged
Root cause: Botnet distribution or attackers using large IP pools; IP-based blocking alone can’t keep up.
Fix: Add per-user throttles, require stronger auth, and focus on detection and rapid response rather than infinite ban lists.
8) Symptom: After “tightening security,” legitimate clients can’t connect
Root cause: Disabled protocols/ports without an inventory of clients (old devices, copiers, monitoring, line-of-business apps).
Fix: Inventory clients, publish supported settings (993/587, TLS required), and provide a migration window. Block legacy access in stages, not with a single Friday-afternoon change.
Checklists / step-by-step plan
Phase 0: Don’t lock yourself out (do this before touching bans)
- Confirm out-of-band access works (cloud console, IPMI, serial). Test login, not just “it exists.”
- Whitelist management egress (VPN, bastion, office) in firewall and fail2ban ignore lists.
- Snapshot current config (copy relevant configs; record current firewall rules and fail2ban jail settings).
- Check disk headroom on
/varand/var/log. Under attack, logs can become the outage.
Phase 1: Stabilize service during active brute force (15–60 minutes)
- Confirm the attack scope: IMAP only, SMTP AUTH only, or both. Use journald or mail.log counts.
- Apply network rate limiting for new connections to 993/587 (carefully; whitelist known shared egress sources).
- Enable/verify fail2ban bans on Dovecot and postfix-sasl. Ensure the log source is correct.
- Enable Dovecot auth throttling to protect the auth backend and CPU.
- Watch conntrack and process limits. If you’re near max, connection shaping is not optional.
Phase 2: Reduce blast radius (same day)
- Identify targeted accounts (shared mailboxes, executives, finance). Treat them as high-risk.
- Reset credentials for accounts with suspicious successful logins, not for everyone “just in case.” Panic resets create support outages.
- Disable IMAP login for shared mailboxes where possible; use delegated access instead.
- Enforce TLS-only and modern ports: IMAPS 993, submission 587. Remove public 143 if feasible.
- Add send rate limits for SMTP AUTH to contain compromised accounts.
Phase 3: Make it stick (next sprint)
- Baseline normal behavior: auth failures/min, connections, typical source regions, typical send rates.
- Alert on anomalies that matter: login success from new ASN/country, spikes in auth failures per user, spikes in outbound volume per user.
- Harden passwords: length, banned passwords, and rotation policy aligned with your identity platform.
- Plan for modern auth if your ecosystem supports it. If not, plan for app passwords and limited scope.
- Run game days: simulate brute force, verify bans, verify whitelists, verify you can still administer the server.
FAQ
1) Should I just block all countries except ours?
If your users never travel and you don’t have global vendors, it can help. In reality, geo-blocking is a speed bump.
Attackers can use domestic IPs too. Use it as one layer, not your plan.
2) Account lockout policies: good idea or foot-gun?
Lockouts can stop brute force but can also enable denial-of-service against users (attackers intentionally trigger lockouts).
Prefer throttling and adaptive risk rules when possible; if you lock out, make it short and monitored.
3) Is fail2ban enough?
Not alone. fail2ban is great against repeat failures from the same IP. It is weak against distributed spraying and stuffing.
Pair it with per-user throttling, strong authentication, and anomaly detection for successful logins.
4) Why not disable IMAP entirely?
Sometimes you can, and it’s glorious. Often you can’t because of legacy clients, shared workflows, or applications that poll IMAP.
If you must keep IMAP, keep it on 993 only, require TLS, and restrict who is allowed to use it.
5) Should I lower password hash cost to reduce CPU usage during attacks?
No. That’s trading long-term security for short-term comfort. Fix the attack path with throttles and rate limiting.
Keep strong hashing; it’s one of the few controls that still matters after a database leak.
6) How do I avoid banning our own VPN or office NAT?
Maintain a small reviewed whitelist, and document it like production code. Add those IPs to fail2ban ignore lists and firewall accept rules.
Then test it quarterly. “We think the VPN egress is still that IP” is not a test.
7) What’s the clearest sign that accounts are actually compromised?
Successful logins from unusual IPs followed by outbound sending spikes, mailbox rule changes (if applicable), or large/fast IMAP fetch patterns.
Also: users reporting “sent mail I didn’t send” is the human monitoring system you didn’t want.
8) Should we move submission to port 465 or 587?
587 is the modern standard for submission; 465 exists and works but can confuse policy and monitoring if you run both.
Pick one as your supported client path, document it, and monitor it well.
9) Can I safely block port 25 to stop attacks?
Blocking inbound 25 breaks mail delivery from other servers unless you relay through a gateway. If you have a mail gateway, great—block 25 on the backend.
If this host is your MX, port 25 stays open. Focus on preventing abuse and protecting resources.
10) What if the attack is making the server unstable and I need immediate relief?
Apply connection rate limits for new connections to 993/587 and temporary bans for top IPs, then verify your admin access still works.
Stabilize first, then tune. Don’t make five architectural changes during the same incident window.
Next steps that won’t bite you later
If you take only a few actions, take these. They’re the reliable kind—the kind you can defend in a post-incident review without sounding like you’re negotiating with physics:
- Reduce the surface: IMAPS (993) and submission (587) are your defaults; stop exposing plaintext IMAP (143) publicly unless you have a hard requirement.
- Stabilize under load: rate-limit new connections, protect conntrack, and throttle authentication before your directory service becomes collateral damage.
- Make fail2ban real: correct logs, correct regex, sane ban windows, and explicit whitelists for shared egress IPs.
- Plan for success cases: watch for successful logins during attacks and clamp down on outbound sending to reduce fraud and blacklisting risk.
- Protect your own access: tested out-of-band console and a documented whitelist are not “nice to have.” They are how you fix production safely.
Then schedule the unglamorous work: baseline normal behavior, inventory clients, and migrate away from legacy auth where you can.
Attackers aren’t creative here. They’re consistent. You can be consistent too—just with better outcomes.