Back to blog
Threat Intel
Phishing Forensics

That Phish Slipped Through. Was a Broken SPF Record to Blame?

An email header's Authentication-Results isn't just noise; it's a forensic trail leading directly to the misconfigurations that let threats through.

MailSleuth Research
Email Security Team
May 29, 20268 min read
An illustration of a torn blueprint for a paper airplane, symbolizing a broken SPF record that prevents proper email del

The phish landed. A user clicked the link. Now you’re staring at a raw email header, trying to connect the dots between a successful credential harvest and the wall of text in front of you. Somewhere in that mess is the answer to *how* this email, which should have been blocked, sailed past your defenses.

More often than you'd think, the initial point of failure isn't a zero-day or a sophisticated evasion technique. It's a typo. A DNS lookup limit exceeded. A misconfigured record published by a marketing team trying to set up a new mail service. These are not exotic failures; they are the bread and butter of daily security operations.

The key is knowing where to look. Let's be clear: the root cause is written down for you in the headers. You just need to know how to read them. The `Authentication-Results` header, in particular, is your Rosetta Stone.

Your First Clue: The `Authentication-Results` Header

Every modern mail gateway—from Microsoft 365 and Google Workspace to standalone Secure Email Gateways (SEGs)—records the results of its email authentication checks in a structured header. This isn't just for fun; it's a critical piece of forensic data, mandated by RFC 8601. It tells you exactly what the receiving server thought of the message's authenticity.

Your first task during analysis is to find this block of text. It's usually near the top of the header stack, just below the most recent `Received` headers. The syntax can vary slightly between vendors, but the core components are the same.

Decoding the Verdict

Authentication-Results: spf=permerror (sender IP is 198.51.100.24) smtp.mailfrom=baddomain.com; dkim=pass (signature was verified) header.d=baddomain.com; dmarc=fail action=quarantine header.from=baddomain.com;

Look at this example. A Microsoft 365 header is a bit more verbose, often including `compauth` results, while Google's is typically more compact. But the gold is right there in the first part: `spf=permerror`. This isn't a simple `pass` or `fail`. It's the server telling you that the sender's SPF record is so badly broken it couldn't even be processed. This is a five-alarm fire drill for an email admin and a huge clue for an analyst.

While `dkim=pass` might seem reassuring, the `dmarc=fail` tells the real story. Because SPF produced an error instead of a pass, and DMARC requires either SPF or DKIM to *align*, the message failed the DMARC evaluation. If the domain's policy was `p=reject`, this `permerror` is the very reason it might have been delivered to junk instead of being blocked outright, as some gateways downgrade enforcement on errors.

Tying the Verdict to the Right Envelope

So you found an SPF failure. The next question is, failure for *what*? A common mistake is to look at the friendly `From:` address in your email client (`header.from`) and assume that's what SPF validates. It's not. That's just a string of text; it can be anything.

SPF, as defined in RFC 7208, validates the sender identity presented during the SMTP transaction itself. Specifically, it cares about one of two things: the `HELO`/`EHLO` hostname or, far more commonly, the address used in the `MAIL FROM` command. This is often called the 'envelope sender,' 'return-path,' or `RFC5321.MailFrom`.

Finding the `smtp.mailfrom`

This is why the `Authentication-Results` header is so useful. It explicitly tells you what it checked. In our example, `smtp.mailfrom=baddomain.com` shows that the SPF check was performed against the domain `baddomain.com`. The IP address of the sending server (`sender IP is 198.51.100.24`) was checked against the SPF record published for `baddomain.com`.

This distinction is critical for understanding Business Email Compromise (BEC). An attacker can put `ceo@yourcompany.com` in the visible `From:` header a thousand times, but if they are sending from their own server, the `smtp.mailfrom` will be something like `attacker@evil-domain.net`. SPF checks `evil-domain.net`. If that domain has no SPF record, or one that authorizes the attacker's server, SPF will pass. DMARC will then fail on alignment because `evil-domain.net` doesn't match `yourcompany.com`, but the initial SPF verdict itself wasn't a `fail`.

When 'Pass' and 'Fail' Aren't the Only Answers

Simple `spf=fail` verdicts are easy to understand: the IP wasn't on the list. But the error codes are more subtle and often point to bigger, more systemic problems. Let's break down the two most important ones from RFC 7208.

Permanent Error (`permerror`)

This means the domain's published SPF record is syntactically invalid. It's un-processable. The most common causes are typos (`ip4` instead of `ip4:`), invalid mechanisms, or publishing more than one SPF record for a domain. The most notorious cause, though, is exceeding the 10 DNS lookup limit. Many organizations bloat their SPF records with nested `include:` statements for every SaaS and marketing platform they use. Each `include:`, `a:`, `mx:`, and `exists:` counts as a lookup. Go past ten, and the record fails to validate, resulting in a `permerror`.

Operationally, a `permerror` is a gift. It's a deterministic failure. You can take the domain from the `smtp.mailfrom` field, plug it into any online SPF validation tool, and it will instantly show you the exact syntax error or which `include:` statement tipped you over the 10-lookup limit.

Temporary Error (`temperror`)

This verdict is more frustrating. It means a transient DNS problem prevented the receiving server from getting a conclusive answer. The SPF record itself might be perfectly valid, but a DNS server along the way timed out, returned a SERVFAIL, or otherwise hiccuped during one of the required lookups.

A `temperror` is a non-decision. Most mail gateways are configured to treat a `temperror` as a neutral or provisionally acceptable result. They can't rightfully block the email because the failure wasn't the sender's fault, but they also can't confirm its authenticity. This is another gap where a malicious email can slip through. If you're seeing persistent `temperror` results from a major partner, it could indicate serious DNS health issues on their end.

The Dangerous Silence of an `spf=none` Verdict

Sometimes you'll find an `Authentication-Results` header with `spf=none`. This is a different beast entirely. It doesn't mean the record is broken; it means there is no SPF record at all. The domain owner has published no policy about who is authorized to send email on their behalf.

In the eyes of a mail server, this is a neutral signal. It cannot fail a check that was never requested. From a security perspective, this is a flashing red light. A domain without an SPF record is trivial to spoof. An attacker can set up a server anywhere, use that domain in the `smtp.mailfrom` address, and a receiving server has no policy-based reason to be suspicious.

A domain with no SPF or DKIM is a domain that cannot use DMARC for enforcement. — A hard truth of email security

This is where DMARC's dependency becomes clear. DMARC (RFC 7489) requires either an aligned SPF check or an aligned DKIM check to pass. If a domain has no SPF record, it can never produce an `spf=pass` result. Its entire DMARC posture then rests on DKIM alone. If a threat actor is sophisticated enough to find a forwarding path that breaks the DKIM signature—like a misconfigured mailing list server that rewrites the message body—they can defeat the entire protection scheme.

Closing the Breach: Remediation and Resilience

Finding the `permerror` was the easy part. The real work is ensuring it doesn't happen again. If the faulty domain is yours, the fix is direct: get into your DNS provider and correct the record. This usually involves 'flattening' the record by replacing `include:` mechanisms with the specific IP ranges they resolve to, or simply removing services you no longer use. Validate the fix with a checker before and after the change.

If the faulty domain belongs to a partner or vendor, your job is notification. Send them a sanitized version of the header, the `Authentication-Results` line, and a link to an SPF validator showing the error. You are doing their security team a favor.

But fixing the record isn't enough. The incident happened. The final step is to use this failure to push for a stronger DMARC policy. If your organization is still at `p=none`, this `permerror` is exhibit A for why you need to move to `p=quarantine` or `p=reject`. A `permerror` on a domain with `p=reject` is far more likely to be handled correctly by receiving gateways. The policy tells the world that you take authentication seriously and that errors should not be tolerated.

The takeaway

An `Authentication-Results` header is a confession. It documents every assumption, every check, every failure that a mail server performed before handing an email to a user's inbox. Learning to read it is not an academic exercise; it's a core incident response skill. The difference between a ten-minute investigation and a two-day goose chase is often the ability to spot `spf=permerror` and know exactly what it implies.

Don't wait for the next phish to practice. Proactively monitoring your own domain's SPF records, and those of your critical supply chain partners, is the only way to stay ahead. As an analyst, your job isn't just to clean up the mess, but to use the evidence to build a better wall. Tools like MailSleuth.AI can automate this continuous analysis, but the foundational knowledge of what these verdicts mean is irreplaceable.

#email-security#spf#dmarc#incident-response#authentication-results#phishing-analysis
MailSleuth Research
Email Security Team

We dissect phishing campaigns and email infrastructure so you don't have to.