Blog · Dmarc
Why Publishing p=reject Without sp= Still Leaves Your Subdomains Open to Spoofing
The Assumption That Causes the Gap
You published v=DMARC1; p=reject; on your root domain. That should stop spoofing everywhere.
Except it doesn't.
The p=reject policy applies to the domain you publish it on. It does not automatically extend to subdomains. Without the sp= tag, subdomains fall through a gap that RFC 7489 technically allows but that receivers handle inconsistently. The result: your root domain is protected, and every subdomain you didn't explicitly cover is not.
Most admins don't discover this until an incident.
What Happens to Your Subdomains When You Publish p=reject Without sp=?
The sp= tag in a DMARC record sets the policy for subdomains. When you publish sp=reject, you're telling receivers: reject mail from any subdomain of your domain that doesn't pass DMARC. When you omit it, you're leaving subdomain policy to the receiver -- and receiver implementations vary.
The difference between these two records is significant:
v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com;
This protects only example.com. Subdomains rely on receiver-specific inheritance rules.
v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com;
This protects example.com and every subdomain that doesn't have its own record.
The sp=reject line is what closes the gap. Without it, subdomains that don't have their own DMARC record are evaluated differently depending on which mail server receives them.
How Receivers Handle Undelegated Subdomains Differently Than You Expect
RFC 7489 Section 6.6.2 describes what receivers should do when a subdomain has no DMARC record of its own: they should apply the parent domain's policy. This is the "tree walking" behavior the spec recommends.
But here's what the spec doesn't make clear: some receivers don't do this reliably. Specifically, when a subdomain has no DNS entry at all -- an undelegated subdomain -- some receivers treat it as a domain with no policy, not as a subdomain that should inherit the parent record.
An undelegated subdomain is a DNS label that exists nowhere in the zone file. It resolves to nothing. No A record, no MX, no TXT. When mail arrives from billing.example.com and billing.example.com doesn't exist in DNS, the receiving server has to decide what to do. Some reject it at SMTP time. Others accept it and apply whatever policy they have for unknown domains.
The ones that accept it are the problem. They create a gap between what your DMARC record says and what actually happens to mail from your subdomains.
The Real Attack Pattern: How Attackers Use Undelegated Subdomains to Bypass DMARC
A client's domain had v=DMARC1; p=reject; on the root. No sp= tag. They believed they were fully protected.
An attacker set up an SMTP server and sent mail claiming to be from billing.clientdomain.com -- a subdomain that had never existed in the client's DNS. No SPF record for that subdomain, no DKIM key, no DMARC record at the label.
The attacker sent thousands of phishing emails over two weeks before someone forwarded a sample.
Why did it work? At the receiving servers the attacker targeted, billing.clientdomain.com returned NXDOMAIN. Those servers treated it as a domain with no DMARC policy, not as a subdomain that should inherit the client's p=reject record. The mail passed through because the receiver had no policy to reject it against.
The fix was three things:
1. Explicit sp=reject in the corporate DMARC record 2. A wildcard DMARC record at *._dmarc.clientdomain.com to catch any subdomain that might get registered 3. A real inventory of every subdomain that actually exists in their DNS, so they could distinguish between "this subdomain doesn't exist" and "this subdomain exists and has no DMARC record"
The Three Fixes That Close the Subdomain Gap
Fix 1: Add sp=reject to your DMARC record
If your current record is:
v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com;
Change it to:
v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com;
One tag closes the subdomain gap. Test it with a p=none period first if you're monitoring, but the fix itself is a single line.
Fix 2: Add a wildcard DMARC record
*._dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com;"
This applies the same policy to any subdomain that doesn't have its own _dmarc record. An attacker who registers a previously-undelegated subdomain will find it already protected.
Fix 3: Audit your actual subdomain inventory
Go to your DNS provider and pull every A, AAAA, MX, and CNAME record. For each subdomain that resolves, check: SPF record? DKIM selector? DMARC record with a policy at least as strict as your root? If a subdomain sends mail and has no DMARC record, that's a gap.
If a subdomain sends mail and has p=none, that's also a gap -- monitoring mode isn't protection.
For large portfolios, this audit becomes a recurring task, not a one-time fix. Subdomains get created, renamed, abandoned. A subdomain without DMARC protection is a gap that attackers will eventually find.
How to Audit What Subdomains Actually Exist vs. What's Published
Start with your DNS zone. Pull every subdomain that has an A, AAAA, MX, or CNAME record. These are the ones that could be used to send mail or to impersonate your domain.
For each one, check:
- Does it have an SPF record?
- Does it have a DKIM selector?
- Does it have a DMARC record with a policy at least as strict as your root domain?
If you manage multiple domains or subdomains, DMARCFlow can monitor these records automatically and alert you when subdomain policy gaps open up -- the exact pattern this attack used. DMARCFlow's domain portfolio monitoring tracks DMARC policy at root and subdomain levels, flags new subdomains that appear without records, and alerts you when a subdomain's policy drops below your configured threshold.
FAQ: p=none, sp=reject, and Common Subdomain DMARC Questions
Does p=reject inherit to subdomains automatically?
No. The p= tag applies only to the domain it was published on. Subdomains are governed by sp= if present, or by receiver-specific inheritance rules if it's absent. If you want subdomains protected, publish sp=reject explicitly. There is no automatic inheritance guarantee across all receivers.
What does sp= mean in a DMARC record?
sp= sets the policy for subdomains of the domain where the record is published. sp=reject means subdomains without their own DMARC record should be rejected. sp=none means they pass without rejection -- useful for monitoring, not for protection.
Does DMARC walk up the domain tree for subdomains?
The RFC recommends that receivers evaluate subdomains against the parent domain's policy when the subdomain has no record of its own. This "tree walking" behavior is recommended, but receiver compliance varies. Some receivers skip it, which is why sp=reject matters.
What's a wildcard DMARC record and do I need one?
A wildcard DMARC record at *._dmarc.example.com applies to any subdomain that doesn't have its own _dmarc record. If you have many subdomains or can't track all of them, a wildcard ensures a policy exists for any subdomain an attacker might try to use. It's not required if you have explicit records for every subdomain, but it's the safest option for most organizations.
How does DMARCFlow help monitor subdomain policies?
DMARCFlow monitors your full domain portfolio and tracks DMARC policy at both root and subdomain levels. It alerts you when a subdomain falls below your configured policy level, when new subdomains appear without DMARC records, and when aggregate reports show authentication failures that indicate a subdomain gap.