Vulnerability analysis · DMARC

OpenDMARC queries DNS with the raw UTF-8 From domain instead of its A-label, so no internationalized domain gets a DMARC policy at all [OpenDMARC ≤ 1.4.2, latest release checked 2026-07-30]

Yongzhe Xu, Virginia Tech  ·  yongzhe@vt.edu  ·  2026-07-31

Spell the victim's IDN in Unicode rather than punycode and OpenDMARC reports dmarc=none. The published p=reject is never found, and every IDN sender is unprotected.

SoftwareOpenDMARC
VendorThe Trusted Domain Project
Sourcehttps://github.com/trusteddomainproject/OpenDMARC
AffectedOpenDMARC 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 behavior. Newest published release checked on 2026-07-30.
WhereDMARC Author Domain extraction, the missing IDNA ToASCII conversion before the _dmarc lookup and alignment
WeaknessCWE-172 (Encoding Error) / CWE-290 (Authentication Bypass by Spoofing)
Reachable byRemote, unauthenticated, no user interaction. One forged, unaligned message.
CVSS v3.1CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N (7.5 (High))
VerificationReproduced 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. Reproduced for Latin (münchen, café), CJK (例え) and a Cyrillic homoglyph, under both p=reject and p=quarantine.

1. Overview

DNS carries no Unicode. A DMARC policy for an internationalized domain can live at one node only, the A-label node, such as _dmarc.xn--mnchen-3ya.example.com. RFC 7489 section 6.6.1 therefore tells the verifier to convert a UTF-8 From domain to its A-label before it queries.

OpenDMARC converts nothing. It sends the query with the raw UTF-8 bytes, gets no answer, and stamps dmarc=none. Any sender on an internationalized domain has its published p=reject or p=quarantine ignored on every OpenDMARC receiver.

2. Analysis

The victim publishes its policy at the only node it can occupy.

_dmarc.xn--mnchen-3ya.example.com.  IN  TXT  "v=DMARC1; p=reject"

Each test sends the same forged, unaligned message: no aligned DKIM, envelope sender bounce@attacker.invalid, SPF -all. Only the spelling of the From domain changes.

From domain formOpenDMARCRspamdRequired
ceo@münchen.example.com (U-label, UTF-8)dmarc=none, delivereddmarc=fail, policy rejectfail
ceo@xn--mnchen-3ya.example.com (A-label, control)dmarc=faildmarc=failfail
ceo@plainmunich.example.com (ASCII, control)dmarc=faildmarc=failfail

Both controls fail correctly, so the U-label spelling is the only variable that flips the verdict. The header OpenDMARC writes shows what happened.

Authentication-Results: receiver.test; dmarc=none (p=none dis=none)
    header.from=münchen.example.com

Two things are wrong in that one header. The policy was abandoned, and the recorded domain is not an A-label, which section 6.6 requires.

One more test locates the defect precisely. Publish the record a second time at the literal raw-UTF-8 node _dmarc.münchen.example.com. OpenDMARC still does not find it. The failure is therefore not a DNS mismatch. OpenDMARC gives up on DMARC for a non-ASCII From rather than normalizing it first.

3. Reproduction

  1. Publish the victim's policy at the A-label node.
_dmarc.xn--mnchen-3ya.example.com.  IN  TXT  "v=DMARC1; p=reject"
  1. Send one forged message, unsigned, with an unaligned envelope sender.
MAIL FROM:<bounce@attacker.invalid>
RCPT TO:<user@receiver.test>
DATA
From: ceo@münchen.example.com
To: user@receiver.test
Subject: payroll update

...
.

Expected: dmarc=fail, disposition reject.

Observed on OpenDMARC: dmarc=none. The message is delivered.

4. Assessment

One missing conversion produces three separate harms.

5. Remediation

Run IDNA ToASCII on the extracted Author Domain. Do it before the _dmarc query and before alignment, and write the A-label into the Authentication-Results header, as section 6.6.1 requires.

The conversion has to include UTS-46 mapping, not just punycoding of labels that hold non-ASCII letters. See opendmarc-unicode-dot-bypass for what the narrower version misses.

6. References