Vulnerability analysis · DMARC
Under *.kawasaki.jp with the exception !city.kawasaki.jp, Rspamd looks for the policy at a _dmarc node the registrant cannot publish at, finds nothing, and reports no policy.
| Software | Rspamd |
|---|---|
| Vendor | Rspamd project (Vsevolod Stakhov) |
| Source | https://github.com/rspamd/rspamd |
| Affected | Rspamd 4.1.2. Originally isolated on 3.10.2 and re-confirmed on 4.1.2 on 2026-07-28. Newest published release checked on 2026-07-30. |
| Where | DMARC organisational-domain computation (get_tld and the Public Suffix List handling in dmarc.lua) |
| Weakness | CWE-346 (Origin Validation Error) leading to CWE-290 (Authentication Bypass by Spoofing) |
| Reachable by | Remote, unauthenticated. One forged, unaligned message against any registrant under such a rule. |
| CVSS v3.1 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N (7.5 (High)) |
| Verification | 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. The rules were verified byte-identical in both verifiers' Public Suffix List files, so the divergence is an algorithm defect and not a data difference. |
The Public Suffix List carries the rule *.kawasaki.jp and the exception !city.kawasaki.jp. Together they make the registrable domain of foo.city.kawasaki.jp equal to city.kawasaki.jp. That node is where the registrant publishes its DMARC policy, and it is the only node the registrant controls.
Rspamd does not apply the * and ! constructs. It takes the organizational domain to be the whole From domain, foo.city.kawasaki.jp. It queries _dmarc.foo.city.kawasaki.jp, which does not exist. It finds no policy and returns DMARC_NA. The forged message is delivered.
The test message has From=foo.city.kawasaki.jp. It is forged and unaligned: DKIM signs with d=attacker and SPF ends in -all. The registrant publishes p=reject at its true organizational node, _dmarc.city.kawasaki.jp.
| From domain | Suffix rules in play | OpenDMARC | Rspamd | Required |
|---|---|---|---|---|
foo.city.kawasaki.jp | *.kawasaki.jp with !city.kawasaki.jp | fail, disposition reject | none / DMARC_NA, delivered | reject |
alpha.pvt.k12.ma.us | static pvt.k12.ma.us, no wildcard or exception | fail, disposition reject | fail, disposition reject | reject |
Rspamd's log option prints the computed value outright: DMARC_NA{foo.city.kawasaki.jp}. The node it queried does not exist, which confirms it never consulted _dmarc.city.kawasaki.jp.
The second row bounds the defect. A statically listed suffix several labels deep is handled correctly, and the two verifiers agree on alpha.pvt.k12.ma.us. Suffix depth is not the problem. The * and ! constructs are.
The list data is not the cause either. Both *.kawasaki.jp and !city.kawasaki.jp are byte-identical in the two containers' list files, and the canonical registrable domain computed from either file comes out as city.kawasaki.jp.
deeper node absent.
# zone: the registrant's real policy, at its true organisational node
_dmarc.city.kawasaki.jp. IN TXT "v=DMARC1; p=reject; sp=reject"
# _dmarc.foo.city.kawasaki.jp does not exist
ceo@foo.city.kawasaki.jp` and an envelope sender in another domain.
Expected: dmarc=fail with disposition reject, because the policy at _dmarc.city.kawasaki.jp applies to the From domain. OpenDMARC on the identical message rejects.
Observed on Rspamd: DMARC_NA, and the message is delivered.
Any registrant sitting under a Public Suffix List * or ! construct has its p=reject or p=quarantine quietly unenforced on Rspamd receivers. Forged mail in that registrant's name is delivered. Conforming verifiers reject the same message.
The registrant cannot see this happening, as with several findings in this set. Their own aligned mail keeps flowing normally. No report surfaces the forgeries.
Implement the Public Suffix List algorithm in full in get_tld. A wildcard rule *.x extends the public suffix by whichever label matched. An exception rule !y.x takes y.x back out of the suffix set, making y.x registrable in its own right. Exception rules win over wildcard rules.
This pairs with opendmarc-psl-wildcard-orgdomain, where OpenDMARC mishandles the same family of rules in the opposite direction. Between the two verifiers both failure modes are covered, so a domain under such a rule is unprotected on one receiver or the other, depending on which one is in front of it.