Summary
This release includes fixes for several reported security
vulnerabilities with CVSS severity ranging Low to High, including
two DMARC verification bypasses. Upgrade is highly recommended.
This release fixes several long-standing issues in go-imap-sql
implementation. Upgrading is highly recommended for anyone using
IMAP implementation. Fixes are fully compatible with 0.9.6 -
messages written by 0.9.7 are readable by 0.9.6 as-is and vice versa.
Now storage.imapsql can store malformed MIME messages. Such messages are
stored as a single-part application/octet-stream message. This can cause
display issues with most IMAP clients but no data is lost.
Security
- dmarc: Fix DMARC bypass when the From domain uses mixed case
(GHSA-qh5c-2mrx-4ppj,
no CVE assigned yet).
Messages whose From domain contained uppercase characters could be checked
against the wrong organizational domain, so the domain’s published DMARC policy
was not applied. An attacker could spoof a domain that publishes p=reject or
p=quarantine and get the message delivered.
Affects configurations using inbound SMTP with dmarc yes (default).
- dmarc: Reject messages without a single valid author domain when DMARC is
enabled
(GHSA-fhw2-mvqf-h69c,
not CVE assigned yet) (#879).
Messages with a malformed or multiple-address From header were treated as
having no DMARC policy and accepted, allowing an attacker to bypass DMARC by
deliberately breaking the From header. The new dmarc_reject_invalid_from
option controls this behavior; it is enabled in the new default configuration,
while existing deployments must enable it explicitly.
Affects configurations using inbound SMTP with dmarc yes (default).
- auth/ldap: Hide whether an LDAP username exists
(GHSA-88mq-x5xv-cmrh;
no CVE assigned yet) (#880).
Unknown usernames previously caused fewer LDAP operations than existing
usernames, allowing unauthenticated clients to enumerate valid accounts through
timing differences. This can aid targeted phishing and credential-stuffing
attacks.
Affects all configurations using auth.ldap.
- proxy_protocol: Trust only the configured host for bare IPv6 addresses
(GHSA-58jf-c377-6r8w;
no CVE assigned yet) (#884).
A bare IPv6 address in the proxy_protocol trust list was treated as a /32
network, trusting unrelated IPv6 peers in the same range. A directly connected
attacker could forge PROXY headers to choose the client IP seen by SMTP/IMAP,
bypassing rate limits and DNSBL checks and falsifying audit logs.
Affects configurations using proxy_protocol on a public-facing endpoints (not
recommended in general).
- limits: Fix a panic when source rate limits are exhausted without IP limits
(GHSA-wcj3-m6rw-7gv9;
no CVE assigned yet).
With a source limit but no ip limit, exhausting the source bucket set made
the cleanup path dereference a nil IP limiter. A remote sender could trigger a
nil-pointer panic, disrupting message acceptance on the affected SMTP endpoint.
Bug fixes
- endpoint/smtp: Replace an invalid
Dateheader with a valid value instead of
rejecting the message during submission preparation (#518). - endpoint/smtp: Recognize wrapped SMTP errors so oversized messages are
reported as "message too large" instead of "internal server error" (#772). - endpoint/smtp: Only clean up session state after a successful commit and
abort failed deliveries, preventing stuck deliveries and spurious "database
is locked" errors (#786). - endpoint/smtp: Fix a shutdown race that could deadlock the server when a
client connected while the endpoint was stopping. - endpoint/smtp: Export the
maddy_smtp_failed_loginsmetric and count failed
AUTH attempts for every SASL mechanism (#868). - smtpconn: Treat wrapped dial errors as temporary network errors, so an
unavailable LMTP server produces a retryable450response instead of a
permanent554(#872) (PR #874, thanks @amlaban65). - storage/imapsql: Fix
APPENDLIMITreporting:STATUSnow returns the
effective per-mailbox limit, the capability is advertised without a value,
and disabling the limit is rejected instead of making clients see a zero
limit incorrectly (#788). - storage/imapsql: Avoid holding a DB write transaction for the whole
delivery and clean up staged messages on failure, reducing “database is
locked” errors with concurrent deliveries andreroute(#786). - storage/imapsql: Treat interrupted deliveries and serialization failures as
temporary errors so the sender retries instead of the message being lost. - storage/imapsql: Fix
SEARCH UNSEENreturning flags from other mailboxes and
missing unseen messages, and fix delivery ignoring the\Seenflag set by
IMAP filters (#591). - storage/imapsql: Fix compound SEARCH queries with multiple excluded flags,
which caused fetchmail to re-download already seen messages (#703). - storage/imapsql: Report messages without
Content-Transfer-Encodingas 7BIT
in BODYSTRUCTURE instead of an invalid NIL value, fixing display in some IMAP
clients (#756). - storage/imapsql: Accept and store messages with malformed MIME structure
instead of failing delivery (#466). - storage/imapsql: Reject attempts to move a mailbox into itself.
- storage/imapsql: Fix a missing transaction commit that left message flags,
such as read/unread state, stale (#712). - target/queue: Fix truncated exponential retry delays so queued mail follows
the documented5min × 1.25^(n−1)schedule (#678). - target/queue: Reduce default
initial_retry_timeto 5m from 15m, add missing
documentation for delay configuration (#678). - target/remote: Fix a panic when checking MTA-STS policies for
internationalized (IDNA) domains. - modify/replace_addr: Apply relative aliases even when the exact address
lookup returns the address unchanged (#734) (PR #871, thanks @mvanhorn). - log: Make
maddy versionand the server startup log report the same version,
including custom builds (#869) (PR #870, thanks @MFAshby). - auth/dovecot_sasl, endpoint/dovecot_sasld: Fix user ID parsing, formatting
and escaping in the Dovecot authentication protocol; the auth server now
passes the authenticated user ID back to Dovecot. - libdns/hetzner: Update to the new Hetzner DNS API; the old API no longer
works (#807).
Improvements
- dns: Reload
/etc/resolv.confwhen it changes (checked at most every five
seconds), so DNS changes from network reconfiguration take effect without
restarting maddy (#475). - target/remote: Log MX/TLS policy decisions at normal log level, including
policy names, effective security levels and rejection reasons, making
outbound delivery issues easier to diagnose (#717). - libdns: Update DNS provider integrations to libdns 1.1 and their latest
releases; leaseweb and gandi use forks upgraded to libdns 1.1, outdates
deprecation warnings were removed. - Dockerfile: Add
bashto the image so thecommandsystem filter can be
used in container deployments (PR #851, thanks @terminar).
Documentation
- tls: Clarify the actual default TLS versions and cipher suites, their
dependence on the Go version, and how to re-enable legacy ciphers for older
servers (#702, #789). - maddy.conf: Point new users to an example aliases file for the
(aliases)
file table syntax (#684) (PR #729, thanks @stellarpower).
Misc
- table: Fix data races in file table reload tests.
- tests: Add a fetchmail interoperability integration test.
- lint: Clean up linter findings in
auth/pam,endpoint/dovecot_sasld,
endpoint/imapand queue tests.