Shieldlist

postfix-dovecot Free

Mail authentication and relay abuse — the parsers for Postfix and Dovecot.

Download the pack tar.gz of the files listed below

Rules (11)

About this pack

Mail authentication and relay abuse, read from a single syslog file where rsyslog routes mail.* — /var/log/maillog on Plesk and Red Hat descendants; /var/log/mail.log on a stock Debian. Category mail. Six rules, translations of the CrowdSec hub's postfix and dovecot scenarios (© CrowdSec, MIT) with the same figures, converted as window ≈ capacity × leakspeed; each rule says where its number comes from. The figures were proven on shared-hosting machines where hundreds of customers mistype passwords all day — quieter hosts only make them safer.

Traditional syslog timestamps (Aug 14 08:49:30), which carry no year: the reader supplies its own, and a line dated ahead of it is taken as last year's.

Read the mail log once. On a machine where /var/log/syslog also carries postfix and dovecot lines, declaring both counts every failure twice and halves every threshold without saying so.

The parsers

parser what it is
postfix-sasl-fail SMTP authentication refused
postfix-relay-denied trying to send mail through this server to elsewhere
dovecot-auth-fail IMAP/POP3/submission login refused
dovecot-password-mismatch the auth process's view, with a truncated hash of what was tried
dovecot-login-ok a login that worked — for weighing negatively

The mailbox name is attacker-controlled and dovecot prints it before the address, so those patterns run greedily to the last rip= on the line. Keep that in anything derived from them.

The rules

The two distinct-password rules need dovecot's auth_verbose_passwords, which is off by default everywhere — no distribution and no panel turns it on for you. Add auth_verbose_passwords = sha1:6 to conf.d/10-logging.conf. Until then they honestly read 0 hits in shield stats, and mail-balance and mail-spray watch the door — or turn on mail-auth-fail, the same count without the hash.

Even with the hash, a login on a mailbox that does NOT exist leaves no hash line: Dovecot has no password to compare. Postfix's own SASL … authentication failed line is the only trace, read by mail-balance, mail-spray and mail-auth-fail.

Policies

Parsers (10)

The building blocks: each parser names a log, a cheap prefilter and the regex that extracts the address.

dovecot-auth-fail mail
# An IMAP, POP3 or submission login refused:
#   imap-login: Login aborted: Connection closed (auth failed, 1 attempts in 2 secs) (auth_failed): user=<admin@example.net>, method=PLAIN, rip=203.0.113.9, lip=192.0.2.1, TLS, session=<...>
#
# `attempts` is how many passwords were refused inside this ONE
# connection: dovecot writes a line per connection, not per try, and
# closes after the third refusal. A rule that wants to count tries rather
# than connections names it with `weight_field: attempts` (2026-09-09).
#
# The mailbox name is chosen by whoever is connecting and is printed
# BEFORE the address, so the pattern runs greedily up to the last
# `rip=` on the line — the one dovecot wrote. A user called
# "x, rip=198.51.100.1, lip=" would otherwise frame a bystander.
parser: dovecot-auth-fail
log: mail
prefilter: "auth failed"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ dovecot(?:\[\d+\])?: (?P<service>[a-z0-9]+)-login: .*\(auth failed, (?P<attempts>\d+) attempts[^)]*\)[^:]*: user=<(?P<user>[^>]*)>, method=\S+, rip=(?P<ip>[0-9a-fA-F.:]+), lip='
time_field: time
time_format: syslog
dovecot-login-ok mail
# A login that worked:
#   imap-login: Logged in: user=<me@example.net>, method=CRAM-MD5, rip=203.0.113.9, lip=192.0.2.1, mpid=..., TLS, session=<...>
#
# Here so that a rule can weigh it NEGATIVELY against failures. On a
# host with real mailboxes that is what separates a phone with a stale
# password — which fails, succeeds, fails, succeeds — from a
# brute-force, which only ever fails. A host with no human mailboxes
# does not need it.
parser: dovecot-login-ok
log: mail
prefilter: "Logged in:"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ dovecot(?:\[\d+\])?: (?P<service>[a-z0-9]+)-login: Logged in: .*rip=(?P<ip>[0-9a-fA-F.:]+), lip='
time_field: time
time_format: syslog
dovecot-password-mismatch mail
# The auth process's own view of the same event, which carries a
# truncated hash of the password that was tried:
#   auth(admin@example.net,203.0.113.9,sasl:plain)<sess>: Password mismatch (SHA1 of given password: 7110ed)
#
# Only present where dovecot is configured with auth_verbose_passwords.
# It is worth reading separately from the login line because the hash
# distinguishes a device with one stale saved password, repeating it for
# ever, from a brute-force rotating a new one every attempt — a rule can
# count DISTINCT hashes.
parser: dovecot-password-mismatch
log: mail
prefilter: "Password mismatch"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ dovecot(?:\[\d+\])?: auth\((?P<user>[^,]*),(?P<ip>[0-9a-fA-F.:]+),[^)]*\)<[^>]*>: Password mismatch \(SHA1 of given password: (?P<password_hash>\w+)\)$'
time_field: time
time_format: syslog
postfix-auth-abort mail
# A client that sent AUTH and hung up. Not a wrong password — that is
# logged as an authentication failure — but a machine asking whether
# this server offers authentication at all, and leaving with the answer.
# 8 809 such lines from 3 742 addresses in a day on one machine
# (2026-09-08).
parser: postfix-auth-abort
log: mail
# Postfix 3.10 writes a `NOQUEUE: ` before the words; 3.7 does not.
# Both are read (2026-09-22: a host on 3.10 never counted one abort).
prefilter: "lost connection after AUTH"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/smtpd\[\d+\]: (?:NOQUEUE: )?lost connection after AUTH from \S+\[(?P<ip>[0-9a-fA-F.:]+)\]$'
time_field: time
time_format: syslog
postfix-auth-ok mail
# A message accepted from an address that authenticated: the sender is a
# customer of this server, whatever else their client does. Nobody fakes
# this line — it takes the password.
parser: postfix-auth-ok
log: mail
prefilter: "sasl_username="
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/smtpd\[\d+\]: [0-9A-F]+: client=\S+\[(?P<ip>[0-9a-fA-F.:]+)\], sasl_method=\S+, sasl_username=\S+$'
time_field: time
time_format: syslog
postfix-connect-abort mail
# A connection opened to the mail server and dropped without delivering
# anything: "lost connection after STARTTLS/EHLO/HELO/CONNECT/UNKNOWN".
#
# AUTH is NOT here, and the name says connect and not starttls for the
# same reason: asking whether the server offers authentication is a
# different act, with its own parser (postfix-auth-abort) and its own
# rule. Counting it here made 833 bans in two days report as "repeated
# rejected delivery attempts" when nobody had tried to deliver anything
# (Robin, 2026-09-09: « faudrait mieux organiser les filtres spam »).
parser: postfix-connect-abort
log: mail
# Postfix 3.10 writes a `NOQUEUE: ` before the words; 3.7 does not.
prefilter: "lost connection after"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/smtpd\[\d+\]: (?:NOQUEUE: )?lost connection after (?:STARTTLS|EHLO|HELO|CONNECT|UNKNOWN) from \S+\[(?P<ip>[0-9a-fA-F.:]+)\]$'
time_field: time
time_format: syslog
postfix-non-smtp mail
# Something that is not a mail client talking to the SMTP port:
#   warning: non-SMTP command from unknown[203.0.113.9]: GET / HTTP/1.1
#   warning: non-SMTP command from unknown[203.0.113.9]: \026\003\001...
#
# HTTP verbs and TLS handshake bytes on port 25 are port scanners and
# exploit probes, never a misconfigured sender. Translated from
# CrowdSec's postfix-non-smtp-command (instant ban).
#
# The hostname before the bracket is rDNS and untrusted; the address
# inside the brackets is what postfix measured.
parser: postfix-non-smtp
log: mail
prefilter: "non-SMTP command"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/smtpd\[\d+\]: warning: non-SMTP command from \S+\[(?P<ip>[0-9a-fA-F.:]+)\]:'
time_field: time
time_format: syslog
postfix-reject mail
# Any recipient postfix refused at smtpd time:
#   NOQUEUE: reject: RCPT from unknown[203.0.113.9]: 454 4.7.1 <x@y>: Relay access denied; ...
#   NOQUEUE: reject: RCPT from unknown[203.0.113.9]: 550 5.1.1 <x@y>: Recipient address rejected: ...
#
# ONE reject is not a verdict — a legitimate correspondent's server
# typoing an address writes this line too, which is why this parser
# belongs in a THRESHOLD rule (CrowdSec models it as a leaky bucket in
# postfix-spam), never in an instant one. Relay attempts specifically
# are covered by postfix-relay-denied, which IS instant-worthy.
parser: postfix-reject
log: mail
prefilter: "NOQUEUE: reject"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/smtpd\[\d+\]: NOQUEUE: reject: RCPT from \S+\[(?P<ip>[0-9a-fA-F.:]+)\]: \d{3} '
time_field: time
time_format: syslog
postfix-relay-denied mail
# Someone trying to send mail through this server to somewhere else:
#   NOQUEUE: reject: RCPT from unknown[203.0.113.9]: 454 4.7.1 <x@example.com>: Relay access denied; from=<...> to=<...>
#
# There is no version of this that is a mistake by a legitimate sender:
# a client that should be relaying authenticates first. The address is
# read from the connection, before the recipient the client supplied.
parser: postfix-relay-denied
log: mail
prefilter: "Relay access denied"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/\S+\[\d+\]: NOQUEUE: reject: RCPT from \S*\[(?P<ip>[0-9a-fA-F.:]+)\]: 45\d 4\.7\.1 '
time_field: time
time_format: syslog
postfix-sasl-fail mail
# An SMTP authentication refused:
#   warning: unknown[203.0.113.9]: SASL LOGIN authentication failed: authentication failure, sasl_username=test@example.net
#   warning: host.example[203.0.113.9]: SASL login authentication failed: ...
#   warning: unknown[203.0.113.9]: SASL NTLM authentication failed: no mechanism available
#
# Postfix writes the mechanism in whatever case it received, so it is
# matched loosely. The address comes from the connection and is printed
# before anything the client chose. The mailbox named (`sasl_username`,
# absent when the client never got that far) is captured as `user` for
# the rules that count distinct mailboxes; it is attacker-controlled.
parser: postfix-sasl-fail
log: mail
prefilter: "SASL"
regex: '^(?P<time>[A-Z][a-z]{2} [ 0-9]\d \d{2}:\d{2}:\d{2}) \S+ postfix/\S+\[\d+\]: warning: \S*\[(?P<ip>[0-9a-fA-F.:]+)\]: SASL \S+ authentication failed(?:.*?, sasl_username=(?P<user>\S+))?'
time_field: time
time_format: syslog

Reports

mail-auth-probe This address opens SMTP sessions to our mail server, asks whether authentication is offered, and hangs up. This is reconnaissance for credential attacks on mail accounts, seen from many addresses at once; blocked. Please check what runs on this address.
# Asking whether the server offers SMTP authentication, and leaving. It
# is what a machine does while it looks for a server that will carry its
# mail — reconnaissance, not a delivery and not a password guess, and it
# must not be reported as either.
report: mail-auth-probe
categories: [port-scan]
says: "This address opens SMTP sessions to our mail server, asks whether authentication is offered, and hangs up. This is reconnaissance for credential attacks on mail accounts, seen from many addresses at once; blocked. Please check what runs on this address."
include: []
mail-intrusion This address is trying passwords on our mail server (SMTP/IMAP/POP or webmail) for mailboxes it does not own — credential brute force or credential stuffing, the way accounts get hijacked to send spam. Every attempt is refused; the address is blocked. Please check the machine for malware or a misused mail client.
# Categories reuse the mapping proven in production by this host's
# CrowdSec notifier. `include` is empty: a report says what happened,
# never who it happened to. The accounts tried, the mailboxes aimed at
# and the site that was hit are all captured by the parsers and none of
# them are a public database's business.
report: mail-intrusion
categories: [email-spam, brute-force]
says: "This address is trying passwords on our mail server (SMTP/IMAP/POP or webmail) for mailboxes it does not own — credential brute force or credential stuffing, the way accounts get hijacked to send spam. Every attempt is refused; the address is blocked. Please check the machine for malware or a misused mail client."
include: []
mail-probe This address repeatedly opens connections to our mail server and drops them without sending anything. This is a scanner or a botnet probing for mail servers to abuse; it ties up connections for nothing and is blocked. Please check what runs on this address.
# What happened, and not what it resembles: a connection was opened to
# the mail server and dropped without delivering anything. Calling that
# spam was wrong — nobody had tried to send a message.
report: mail-probe
categories: [port-scan]
says: "This address repeatedly opens connections to our mail server and drops them without sending anything. This is a scanner or a botnet probing for mail servers to abuse; it ties up connections for nothing and is blocked. Please check what runs on this address."
include: []
mail-relay This address is trying to send mail through our server to recipients we do not host — probing for an open relay in order to send spam through us. Every attempt is refused and the address is blocked. Please check the machine for spamware or a misconfigured mail application.
# An open-relay attempt: recipients this server does not host, one after
# another. Distinct from mail-spam, which is about volume.
report: mail-relay
categories: [email-spam]
says: "This address is trying to send mail through our server to recipients we do not host — probing for an open relay in order to send spam through us. Every attempt is refused and the address is blocked. Please check the machine for spamware or a misconfigured mail application."
include: []
mail-spam This address keeps trying to deliver mail our server rejects — spam, or a walk through mailboxes that do not exist to find valid addresses (directory harvesting). Refusal after refusal from one address is abuse, not a mistake; blocked. Please check the machine for spamware or a compromised account.
report: mail-spam
categories: [email-spam]
says: "This address keeps trying to deliver mail our server rejects — spam, or a walk through mailboxes that do not exist to find valid addresses (directory harvesting). Refusal after refusal from one address is abuse, not a mistake; blocked. Please check the machine for spamware or a compromised account."
include: []

Files