Vulnerability analysis · DKIM verification
Two bytes are enough. If the first line of the message begins with a space or a tab, dkim.DKIM().verify() raises an uncaught IndexError.
| Software | dkimpy |
|---|---|
| Vendor | dkimpy maintainers (Scott Kitterman et al.) |
| Source | https://launchpad.net/dkimpy |
| Affected | dkimpy 1.1.8 (the version tested); the parsing code is long-standing and earlier releases are expected to be affected. Newest published release checked on 2026-07-30. |
| Where | dkim/__init__.py, rfc822_parse(), line 372 |
| Weakness | CWE-248 (Uncaught Exception) |
| Reachable by | Remote, unauthenticated. One inbound e-mail whose first byte is a space or tab. |
| CVSS v3.1 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5 (High)) |
| Verification | Confirmed with a two-byte proof of concept under coverage-guided fuzzing. |
A header line that begins with whitespace is a continuation of the header above it. rfc822_parse() handles one by appending it to the previous header, with headers[-1][1] += .... If the whitespace line is the first line of the message, there is no header above it. headers is still an empty list, and indexing it with -1 raises IndexError.
Nothing catches that exception and nothing converts it to the library's own DKIMException. It travels out of DKIM.verify() to the caller. The documented contract tells callers to catch DKIMException, so an application that followed the documentation does not catch this one and dies.
The input does not have to be a valid message, a signed message, or even a plausible one. The first byte decides. A leading space or tab is read as a folding continuation of a header that was never parsed, and the empty-list index follows immediately.
>>> import dkim
>>> dkim.DKIM(b" \r\n").verify(dnsfunc=lambda n, **k: b"")
Traceback (most recent call last):
...
File ".../dkim/__init__.py", line 372, in rfc822_parse
headers[-1][1] += line
IndexError: list index out of range
involved; the parser fails before that point.
import dkim
dkim.DKIM(b" \r\n").verify(dnsfunc=lambda n, **k: b"") # IndexError
dkim.DKIM(b"\tx\r\n").verify(dnsfunc=lambda n, **k: b"") # IndexError
Expected: a malformed message is rejected through the library's documented error type, DKIMException or a subclass of it.
Observed: IndexError: list index out of range from rfc822_parse() at dkim/__init__.py line 372.
Two bytes are enough. Space and tab both do it.
Exposed is any application that hands untrusted message bytes to dkim.DKIM() or dkim.verify() and catches only DKIMException, which is what the documentation instructs. The attacker needs to deliver one message whose first byte is a space. No authentication, no valid signature, no knowledge of the target's configuration.
The result in a mail filter is a processing failure on that message. In a single-threaded filter it is a service outage. How bad it gets depends on how the calling application handles an unexpected exception, which this report does not attempt to enumerate.
Reach extends past direct users of the library. authheaders depends on dkimpy, and so do several Python mail filters.
Treat a continuation line that has no header above it as a malformed message. Do not index an empty list.
if line[0] in b' \t':
if not headers:
raise MessageFormatError("continuation line before any header")
headers[-1][1] += line
Raising the library's own exception type keeps the documented contract intact. If bug-compatibility with permissive parsers matters more, drop the stray line silently instead.