Skip to content
Oct 6, 2026NewsletterRSS

KumoMTA Closes Crash and Header Forgery Holes in One Release

KumoMTA 2026.09.29 fixes remotely triggerable crashes and a forged-header flaw, and now drops any log record over 128 MiB by default.

3 min read

KumoMTASelf-hosted

Hand-drawn illustration of a mailbox with a cracked padlock and a magnifying glass on a green background

KumoMTA’s 2026.09.29 release fixes crashes that a remote sender or domain could trigger, according to the changelog from Kumo Corp, the company behind the open source mail server. It also closes a header injection flaw and changes how large log records are handled.

A remote domain could crash the outbound path

A destination domain could publish an MTA-STS policy with a max_age large enough to overflow the expiry calculation and abort the process, the notes say. The message stayed spooled and was retried. The crash looped on the outbound path. The value is now clamped to the RFC 8461 maximum of 31,557,600 seconds.

A message with two or more DKIM-Signature headers whose b= tags differed in length could panic inbound DKIM verification through msg:dkim_verify(). Kumo Corp said the per-message signature limit now counts parsed signatures too. Deeply nested comments in structured headers could overflow the stack, and MIME content nested more than 100 levels is now kept as an opaque part.

A forged header could split Authentication-Results

Kumo Corp said control characters in values could split the Authentication-Results header that KumoMTA adds, forging a result line or pushing real headers into the body. The sources included a sender-controlled DMARC record and a malformed inbound ARC header. The encoder now strips control characters from every value it writes. The notes credit the reporter, @raphting.

Two smaller fixes sit in the same area. An SPF record with a /0 prefix now matches every address, and an out-of-range CIDR length such as ip4:0.0.0.0/33 is rejected at parse time. Before, such records matched the wrong range with no error. Kumo Corp said the domain owner controls that record anyway. An unrelated party could not use the flaw to defeat the check.

Log records over 128 MiB are now dropped

The one breaking change is a size cap on log records. kumo.configure_local_logs now enforces max_record_size, default 128 MiB, and drops a larger record instead of writing it. A log_record_dropped_too_large metric counts the drops. The write_line and write_record calls in kumo.jsonl.new_writer now raise an error at the same size.

The old reader was fixed at roughly 128 KiB. Records above that were silently unreadable. A new max_line_size setting lets the reader handle records up to 128 MiB, and the tailer no longer discards the rest of a segment when it meets a large one. Senders who log big payloads should raise max_record_size before upgrading.

Message handling fixes

Kumo Corp fixed quadratic CPU cost in two paths: repairing bare line endings, and rebuilding messages with many Content-Type parameters. A crafted header could pin a CPU. Headers accepted from one block are now capped at 1,000.

Rebuilt multipart messages no longer swap \r\n for \n\r ahead of the first boundary, a bug that broke DKIM signatures. Constructed messages now emit MIME-Version in its uppercase form. Spam filters such as rspamd score the mixed-case spelling.

Key takeaways

  • KumoMTA 2026.09.29 fixes remotely triggerable crashes in MTA-STS, DKIM verification and header parsing.
  • A header injection flaw in Authentication-Results is closed.
  • Log records over 128 MiB are now dropped by default.
  • SPF /0 and out-of-range CIDR handling is corrected.

The take

We think the MTA-STS crash is the one to understand. A mail server must read data that strangers control, such as DNS records and headers. One bad value can then stop the whole process. A retry queue makes it worse: the same message brings the crash back after every restart.

The log change shows a second principle. A limit on only one side, here a reader fixed near 128 KiB, produces data that was written but cannot be read. Setting both sides to the same number is the right repair.

Operators should upgrade, then check their logs for records near the new limit and watch log_record_dropped_too_large for a week.