Author: Weitong Li, Virginia Tech <weitongli@vt.edu>
Date: 2026-07-31
Vendor: The Trusted Domain Project
Software: OpenDMARC
Source code: https://github.com/trusteddomainproject/OpenDMARC
Affected version: OpenDMARC 1.4.2, built from the upstream tarball rel-opendmarc-1-4-2. The finding was originally isolated on the Debian package 1.4.2-1+deb12u1 and re-confirmed against pristine upstream. Earlier 1.4.x and 1.3.x releases are expected to share the behaviour. Latest version tested on 2026-07-30.
Vulnerable component: DMARC Author Domain extraction — the missing IDNA ToASCII / UTS-46 mapping step before the _dmarc lookup
Vulnerability type: CWE-1289 (Improper Validation of Unsafe Equivalence in Input)
Attack vector: Remote, unauthenticated, no user interaction. One forged, unsigned message.
CVSS v3.1: 7.5 (High) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Status: Reproduced on 2026-07-28 against the current release (run 20260728-120957) with a scripted reproducer, negative controls, and a second independent implementation as the differential oracle. Confirmed 6 of 6 under a real registrable .com domain, with an IDNA reference oracle.
Impact. A single fullwidth full stop (U+FF0E) in the From domain turns a p=reject policy into dmarc=none, with no attacker credentials of any kind.
Complete DMARC bypass against any plain-ASCII domain publishing p=reject or p=quarantine, on any receiver running OpenDMARC. The attacker needs no DKIM key, no control of the victim's DNS, and no relationship with the victim — only the ability to send mail, which is to say no credentials at all. The visible From: in the recipient's mail client renders as the victim's domain to any reader who does not inspect the individual code points.
This is the most broadly exploitable of the behavioural findings, because the precondition is merely that the victim has deployed DMARC.
RFC 7489 section 6.6.1 is a MUST: “If the domain is encoded with UTF-8, the domain name MUST be converted to an A-label, as described in Section 2.3 of [IDNA], for further processing.” IDNA ToASCII performs UTS-46 compatibility and separator mapping before punycoding.
OpenDMARC omits the step entirely. A From: domain written with a Unicode character that NFKC/UTS-46 maps onto the victim's ASCII organisational domain is treated as an unrelated, unknown domain: no _dmarc record is found, and the verdict is dmarc=none. The victim's p=reject is not applied and the forgery is delivered.
The victim population is not limited to owners of internationalised domains. It is every plain-ASCII DMARC-protected domain, because the malicious From folds down to the ASCII organisational domain.
Against a plain-ASCII organisation publishing p=reject, with a forged, unsigned, unaligned message, only the From domain varies:
| From domain form | OpenDMARC | Rspamd | IDNA reference |
|---|---|---|---|
vic.example.com (plain ASCII, control) | fail | fail | fail (consensus) |
vic.example.com (U+FF0E fullwidth full stop) | none — fail-open | fail | folds to the ASCII organisation |
vic。example。com (U+3002 ideographic full stop) | none | fail | folds to the ASCII organisation |
vic。example。com (U+FF61 halfwidth ideographic full stop) | none | fail | folds to the ASCII organisation |
vic.example.com (fullwidth letters, NFKC to vic) | none | fail | folds to the ASCII organisation |
The Authentication-Results header OpenDMARC writes for the U+FF0E case records the raw fullwidth bytes, which shows directly that no mapping took place:
Authentication-Results: receiver.test; dmarc=none (p=none dis=none)
header.from=vic.example.com
Two controls make the mechanism airtight. An ASCII-dot From equal to the victim organisation makes both verifiers fail, proving both are able to perform the lookup at all. The same compatibility forms with no policy published make both return none, isolating the published p=reject as the only variable that diverges. The run was repeated on two fresh random domain suffixes to exclude DNS or policy caching.
Publish, for a victim organisation under a real registrable suffix:
_dmarc.vic.example.com. IN TXT "v=DMARC1; p=reject; adkim=s; aspf=s"
Send an unsigned message from an unrelated host, with an envelope sender in an unrelated domain and no aligned DKIM signature:
MAIL FROM:<bounce@attacker.invalid>
RCPT TO:<user@receiver.test>
DATA
From: ceo@vic.example.com <- U+FF0E instead of '.'
To: user@receiver.test
Subject: invoice
...
.
Expected under RFC 7489 section 6.6.1: ToASCII maps U+FF0E to ., the organisational domain resolves to vic.example.com, the policy is found, alignment fails, and the verdict is dmarc=fail with the reject disposition. Observed on OpenDMARC: dmarc=none, message delivered. Rspamd on the identical message returns dmarc=fail.
Perform IDNA ToASCII with UTS-46 processing on the extracted Author Domain before the _dmarc query and before alignment, as RFC 7489 section 6.6.1 requires.
A partial fix is not enough here. Converting only when a label contains non-ASCII letters resolves the related U-label case but leaves this one open, because the malicious characters are separators and compatibility forms that must be NFKC/UTS-46 mapped to ASCII before the registrable domain is even recognisable.
Closely related to opendmarc-ulabel-not-converted, which is the same missing conversion reached through a different equivalence class. That entry requires the victim to own an internationalised domain; this one does not, which makes its victim population strictly broader. Both should be fixed by the same change.
A recorded negative result: the NFC-versus-NFD question is a consensus, not a bug. For an internationalised victim with its policy at the NFC A-label node, Rspamd NFC-normalises an NFD From and finds the policy, and OpenDMARC fails both forms identically, which is simply the U-label case again with no additional asymmetry.