What's Changed
- Strip control characters from the MIME type, charset, transfer encoding, micalg and protocol arguments of the message-building API, as is already done for attachment filenames -- thanks @manus-pi, @AlpetGexha and @kemrec
- Add configurable limits on the total number of headers, header bytes and header tokens parsed in a message, each recording a parse error when reached (override via DI config):
maxMessageHeaderCount(default 50000) — maximum headers read per message across all partsmaxMessageHeaderSizeBytes(default 8388608) — maximum header bytes read per message across all partsmaxMessageHeaderTokenCount(default 250000) — maximum header tokens parsed per message across all parts; headers parsed after it is reached are kept as one unparsed token each
- Read past the rest of a part's headers when a header limit is reached, rather than treating them as the part's content
- Skip building the error logging context when no logger is configured
- Lower the default
maxMessagePartCountfrom 10000 to 1000 - Parse quoted header values in O(n) rather than O(n²) -- thanks @manus-pi
- Parse address groups and RFC 2231 split parameters in O(n) rather than O(n²)
- Match multipart boundary lines in constant time regardless of nesting depth
- Parse each part's Content-Type header once rather than twice
- Keep only the mime-encoded header parts that recorded decoding errors, rather than every part
- Strip control characters from uuencoded part filenames and from the remaining message-building helper arguments
Security
This release fixes two reported vulnerabilities:
- GHSA-gmgm-r6fh-fq6g -- header injection through message-building arguments not covered by the fix for CVE-2026-61815.
- GHSA-fcgh-j754-jh42 -- uncontrolled resource consumption (CPU/memory) when parsing untrusted messages, not covered by the fixes for CVE-2026-61816 and GHSA-pmx8-5pxm-f2r6.
Reported by @manus-pi, @AlpetGexha and @kemrec; the unbounded per-message header memory was found during the resulting review. Upgrading is recommended.