DKIM Replay: A Valid Signature Is Not Consent

In April 2025, phishing emails arrived from no-reply@google.com with a valid Google DKIM signature and a DMARC pass. Nothing was forged. That's the problem with DKIM.

In April 2025, people started receiving security alerts from no-reply@google.com. The kind Google actually sends. The message warned that a law-enforcement subpoena had been served on the recipient’s Google account and linked to a support page to review the case. The From address was real. The DKIM signature verified against Google’s key. SPF passed, DKIM passed, DMARC passed. Gmail displayed it in the same conversation thread as legitimate Google security notices, with no warning of any kind.

None of it was forged. That’s the part worth sitting with. The attacker didn’t spoof Google — spoofing implies faking something, and nothing here was faked. Every authentication check the industry spent twenty years building returned green, on a phishing email, because the email carried a genuine, valid, Google-issued DKIM signature. The signature was real. It just wasn’t doing what everyone assumes a signature does.

What the signature actually attests

DKIM (RFC 6376) works by having the sending domain sign a message with a private key and publish the public key in DNS. The signer picks a set of headers — typically From, Subject, Date, a few others — and the body, computes a signature over them, and staples it into a DKIM-Signature header. A receiver fetches the public key, recomputes the hash, and if it matches, one fact is established: the domain that holds this key signed this exact content.

Read that fact carefully, because it is narrower than it feels. It says the content was signed by the domain. It does not say who sent this particular copy, or to whom, or how many times, or whether the domain intended for you to receive it. DKIM authenticates the message. It does not authenticate the act of sending the message to you. Those are different things, and the entire replay attack lives in the gap between them.

A DKIM signature has no notion of a recipient. Even when the To header is signed, nothing stops the message from being delivered somewhere else — the signature stays valid over the bytes it covered regardless of where the envelope actually routes it. There’s no counter, no nonce, no “this signature is good for one delivery.” A validly signed message is a bearer token: whoever holds a copy can present it, and it verifies. Forever, unless the signer took specific steps to limit it, and almost nobody does.

How you replay a signature

Once you see DKIM as a bearer token, the attack writes itself. You don’t break the crypto. You get the target domain to sign something for you, keep the signed message intact, and re-send it to your victims. The original signature travels with it and verifies against the real domain’s key. To the receiver, it’s authenticated mail from that domain, because by DKIM’s own definition, it is.

The Google campaign is a clean illustration of how little you need. The attacker registered a Google account and created an OAuth application, and set the application’s name to the entire phishing message — the subpoena text, the lot. Naming an OAuth app triggers Google to send a genuine security notification about it, and Google dutifully signed that notification with its own DKIM key. Now the attacker held a real, Google-signed email whose visible content was their phishing lure. They relayed it onward to their targets through infrastructure that left the message and its signature byte-for-byte intact. It landed as authenticated mail from no-reply@google.com, because that’s exactly what it was. The link pointed at a fake support portal hosted on sites.google.com — Google’s own free site builder — so even the destination sat on a google.com property.

The mechanics vary; the shape doesn’t. Attackers have run the same play by signing a message through a large provider’s outbound servers and then blasting it from their own, and by exploiting messages that sign only part of the body so new content can be bolted on afterward. In every version, the reputation of a trusted domain gets stapled to mail that domain never meant to send to you.

Why the defenses are all patches

This is where it gets uncomfortable, because the fixes are real but each one is a workaround for a protocol that was never designed to prevent this. RFC 6376 even names replay in its security considerations. It was a known limitation from the start, not a bug discovered later.

There’s an expiration tag, x=, that sets a signature’s expiry as a Unix timestamp. Shrink the window and a stolen signature is only useful for a few hours. But the spec says a verifier may treat a signature as expired after x= — it isn’t required to — and RFC 6376 explicitly states that signature expiration is not intended as a standalone anti-replay defense. You’re leaning on optional behavior for a guarantee the standard tells you it doesn’t provide.

There’s oversigning. When a signer lists a header in the h= tag more times than it actually appears, it asserts that no additional copy of that header may be added later; slip one in and the signature breaks. It’s the standard defense against attackers appending headers to a signed message, and you should do it. But it hardens the message against modification — it does nothing about a message replayed completely unchanged, which is the whole trick in the Google case. Nothing was modified there.

And there’s the reputation layer itself, which is the cruel irony. Gmail leans heavily on domain reputation to decide what reaches the inbox. That’s a reasonable design — a valid signature from a domain with a spotless twenty-year record should count for something. Replay turns that strength into the payload. The better a domain’s reputation, the more a stolen signature from it is worth. You can rate-limit how often a given signature is honored, oversign, expire aggressively, and you should do all of it — but you’re managing a symptom of a signature that means less than everyone treats it as meaning.

The actual fix is a new protocol

The IETF’s answer is not another tag. It’s a redesign. The DKIM working group was rechartered to tackle replay directly, starting with a formal problem statement, and the longer arc is DKIM2 — an effort to rework email authentication and address the shortcomings of the SPF, DKIM, DMARC, and ARC stack we’ve been patching for two decades. Whatever DKIM2 becomes, the interesting admission is structural: the people who maintain DKIM looked at replay and concluded you can’t tag your way out of it. The signature has to carry more meaning — about the send, not just the content — and that means changing the protocol, not the config.

That’s years away, and email being email, adoption will be slower than that. In the meantime the lesson is the one the padlock icon should have taught us already: a green checkmark answers exactly one question, and it’s usually a narrower question than the one you’re actually asking. DKIM tells you a domain signed these bytes. It was never going to tell you that domain wanted you to have them. For twenty years that gap didn’t matter much, because nobody was bothering to exploit it. In April 2025, at Google’s expense, somebody did — and the checkmark stayed green the entire time.

Continue the conversation

← Back to Blog