This repository was archived by the owner on Mar 27, 2026. It is now read-only.
Security hardening: constant-time auth, MIME depth limit, BDAT size enforcement#99
Open
kodareef5 wants to merge 4 commits intoExim:masterfrom
Open
Security hardening: constant-time auth, MIME depth limit, BDAT size enforcement#99kodareef5 wants to merge 4 commits intoExim:masterfrom
kodareef5 wants to merge 4 commits intoExim:masterfrom
Conversation
spa.c:263 compares the 24-byte NT Response with memcmp(), which returns early on the first byte mismatch, leaking timing information about how many bytes are correct. Replace with a constant-time XOR accumulation loop that examines all 24 bytes regardless of match position.
The CRAM-MD5 authentication handler compares the client-supplied hex-encoded HMAC-MD5 digest against the server-computed digest using an early-return loop that exits on the first mismatched byte. This leaks how many leading bytes are correct through timing differences. Apply the same constant-time comparison pattern used in the SPA/NTLM fix (spa.c): accumulate mismatches via volatile XOR so all 16 bytes are compared regardless of match position.
mime_acl_check() recursively processes nested MIME multipart structures with no depth limit. A crafted message with thousands of nested multipart boundaries causes stack exhaustion and crashes the Exim process handling the connection. A 1MB message can embed over 17,000 nesting levels, far exceeding the typical 8MB stack. Add a depth check using the existing parent pointer chain in mime_boundary_context. The limit of 100 is far beyond any legitimate MIME nesting while preventing stack overflow.
In the BDAT/CHUNKING receive path, MAX is used where MIN should be when calculating how many bytes to read. This reads the GREATER of the remaining chunk data or the remaining size limit allowance, allowing data to exceed the configured message_size_limit before the late check at line 1122 catches it and rejects the message. The excess data is written to the spool filesystem before rejection, enabling temporary disk space exhaustion beyond the admin's intended limit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four security fixes across Exim's authentication, MIME processing, and BDAT handling:
1. Constant-time NTLM NT Response comparison (
spa.c)The SPA/NTLM authentication handler compares the 24-byte NT Response digest using a loop that returns on the first mismatch, leaking correct byte count through timing. Replaced with volatile XOR accumulation over all 24 bytes.
2. Constant-time CRAM-MD5 digest comparison (
cram_md5.c)The CRAM-MD5 handler compares the 16-byte hex-encoded HMAC-MD5 digest with an early-return loop. Same timing side-channel as the NTLM case. Applied the same volatile XOR pattern.
3. MIME nesting depth limit (
mime.c)mime_acl_check()recursively processes nested MIME multipart structures with no depth limit. A crafted message with thousands of nested boundaries (achievable in ~1MB) causes stack exhaustion and crashes the process. Added a depth limit of 100 using the existingparentpointer chain inmime_boundary_context.4. BDAT message size limit enforcement (
receive.c)MAXis used whereMINshould be when calculating BDAT read length, allowing data to exceedmessage_size_limitbefore the late check rejects it. The excess is written to spool before rejection, enabling temporary disk exhaustion beyond the configured limit.