Case Study 1: Meridian's Email Authentication Rollout

"We were watching attackers spoof our own name to our own customers — and we had the tools to stop it sitting unused in DNS." — Sam Whitfield, Security Engineer, Meridian Regional Bank (constructed)

Executive Summary

The phishing near-miss that opened this book taught Meridian's leadership an uncomfortable lesson: the bank's name was a weapon anyone could pick up. While that first attacker impersonated a third-party title company, Dana Okafor's team quickly discovered, by reading the first DMARC reports they ever collected, that other attackers were actively spoofing meridianbank.example itself — sending fraudulent "your account is locked" and "verify your wire" messages to customers and staff, with the bank's own domain in the From: line. SMTP let them. Nothing in Meridian's mail flow checked whether a sender claiming to be the bank actually was.

This case study follows the security engineering team — Sam Whitfield leading, junior analyst Theo Brandt assisting, GRC analyst Elena Vasquez handling the policy and regulatory framing — through a one-quarter project to deploy SPF, DKIM, and DMARC to full enforcement (p=reject) without breaking a single one of the bank's legitimate mail streams, and to stand up the web-hardening baseline and DNS controls alongside it. It is a build case study: you will watch a correct, careful rollout, see exactly where it nearly went wrong, and learn why the unglamorous "listening" phase is the part that separates a successful deployment from a self-inflicted outage. All names, figures, and records are constructed for teaching (Tier 3); the domains and IPs use documentation ranges.

Skills applied: SPF/DKIM/DMARC record authoring; the DMARC deployment ladder; reading aggregate reports to find both attackers and broken internal streams; sequencing a rollout to avoid breaking legitimate mail; HTTP security-header and DNSSEC/sinkhole deployment; translating a technical control into a board- and regulator-legible win.

Background

Meridian, as established, is a mid-size regional bank: ~1,800 employees, ~120 branches, ~2.5M customers, a hybrid on-prem/AWS/M365 environment, and a compliance surface that includes GLBA, PCI-DSS, and FFIEC examination. Its email is a mix: a Microsoft 365 tenant for most staff, two legacy on-prem mail servers that still handle certain core-banking notifications, and — this is the part that always bites — a long tail of systems that send mail without anyone thinking of them as "mail."

When Sam inventoried Meridian's outbound mail, he found six distinct senders, which is a very normal number and the reason DMARC rollouts are harder than they look:

# System Sends as How it sends
1 Microsoft 365 (staff mail) meridianbank.example Cloud, M365's own infrastructure
2 On-prem mail servers (core notices) meridianbank.example 203.0.113.10, 203.0.113.11
3 Marketing platform meridianbank.example Cloud SaaS, _spf.cloud-mail.example
4 Helpdesk ticketing meridianbank.example Cloud SaaS, separate IPs
5 HR / benefits system meridianbank.example Vendor-hosted
6 Branch document scanners meridianbank.example Email PDFs via a small on-prem relay

Every one of these claims to be meridianbank.example. Some authenticate cleanly; some do not; and on day one, nobody knew which was which — because the bank had never published DMARC and so had never collected a single report on its own mail. That ignorance is the real starting condition, and it is why the project's first move is not to publish a policy but to publish a listening post.

🔗 Connection: This project builds directly on the network architecture and perimeter work of Chapters 6 and 7. The on-prem mail servers sit in a defined network zone; the secure email gateway is a chokepoint in the spirit of the firewall from Chapter 7. Email authentication is the application-layer complement to those network-layer controls — the same defense-in-depth philosophy, one layer up.

The Rollout

Phase 1 — Publish SPF and DKIM, and a DMARC listening post

Sam's first deliverable is the foundation the other two stand on. He publishes Meridian's SPF record, deliberately starting with the cloud and on-prem sources he is certain of, and authorizing the cloud providers by include rather than chasing their IPs:

meridianbank.example.  IN  TXT  "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 include:spf.protection.outlook.example include:_spf.cloud-mail.example -all"

He chooses -all (hard fail) from the start, which some teams avoid out of nervousness. His reasoning is sound: SPF failure on its own does not bounce mail at most receivers unless a DMARC policy tells it to, and Meridian's DMARC is about to be p=none — so a hard-fail SPF is safe to publish now and correct later. Starting soft (~all) and "tightening later" is a tightening that, in practice, never happens.

He enables DKIM signing on M365 and on the on-prem servers, publishing the public keys at selectors:

selector1._domainkey.meridianbank.example.  IN  TXT  "v=DKIM1; k=rsa; p=MIGfMA0...EXAMPLE...AQAB"
selector2._domainkey.meridianbank.example.  IN  TXT  "v=DKIM1; k=rsa; p=MIGfMA0...EXAMPLE...AQAB"

Then — and this is the keystone of Phase 1 — he publishes DMARC in monitor-only mode with reporting turned on:

_dmarc.meridianbank.example.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@meridianbank.example; pct=100"

p=none takes no action. Its entire job right now is the rua= address: it asks every receiving mail provider on the internet to send Meridian a daily XML summary of all mail claiming to be from meridianbank.example and whether it authenticated. Sam has, in effect, turned on a global sensor for abuse of the bank's name — without yet changing how a single message is handled.

⚠️ Common Pitfall: Theo, eager, asks why they don't just publish p=reject immediately and "stop the spoofing today." Sam walks him through the trap: at least three of the six legitimate senders almost certainly fail authentication right now, and p=reject would cause receivers worldwide to bounce that legitimate mail — customer statements, helpdesk replies, HR notices. "We'd stop the attackers and the bank's own email in the same minute, and guess which outage the CEO hears about first." Enforcement without listening is how teams take themselves down. The discipline: enforce, but only after you know what enforcement will break.

Phase 2 — Read the reports; find the attackers and the broken streams

After two weeks of p=none, the dmarc-reports@ mailbox is full of XML. Theo runs it through a parser (the kind of triage logic in code/example-02-dmarc-report-triage.py) and produces a consolidated view. A representative day:

DMARC aggregate — meridianbank.example — sampled day — multiple receivers
source_ip          count   SPF    DKIM   aligned?   bucket
203.0.113.10        842    pass   pass   yes        OURS — healthy (on-prem core)
spf.protection...   1,204  pass   pass   yes        OURS — healthy (M365 staff)
198.51.100.50       127    pass   pass   yes        OURS — healthy (marketing)
198.51.100.99        88    fail   pass   yes        OURS — helpdesk, SPF GAP (DKIM saves it)
198.51.100.140       63    fail   fail   no         OURS — HR system, NOT authenticating at all
203.0.113.50         41    fail   fail   no         OURS — branch scanner relay, misconfigured
192.0.2.77          210    fail   fail   no         UNKNOWN — spoofing meridianbank.example
185.x (varies)       95    fail   fail   no         UNKNOWN — spoofing, many source IPs

Reading this table is the central skill of the whole project, and it splits cleanly into two jobs.

The attackers. The rows marked UNKNOWN — 192.0.2.77 and a rotating set of others — are messages claiming to be from the bank, failing every check, sent from infrastructure Meridian does not own. This is live spoofing of meridianbank.example, more than 300 messages in the sampled day, aimed at customers and staff. It is exactly what DMARC enforcement will kill. Theo also pivots on these: the SOC checks whether any of the spoofed lures match reports from the new phish-report button, and feeds the malicious sending IPs and look-alike domains into the DNS sinkhole and the gateway blocklist.

The broken streams. Just as important, three of Meridian's own systems are failing:

  • The helpdesk (198.51.100.99) fails SPF — its IP was never added — but passes DKIM, so it is currently surviving by luck. Fix: add it to SPF (or, better, route it so it aligns properly).
  • The HR system (198.51.100.140) fails both SPF and DKIM — it is not authenticating at all. Fix: add to SPF and enable DKIM signing with the vendor.
  • The branch scanner relay (203.0.113.50) fails both. This one is the nasty surprise, discovered only because of the listening phase: an old relay nobody remembered, emailing scanned loan documents, on an IP not in any record.

🛡️ Defender's Lens: Notice that the DMARC report did the SOC's reconnaissance for them. Without spending a dollar on a new tool, Meridian now has (a) a list of who is spoofing its domain, refreshed daily, and (b) a complete map of its own mail senders, including ones the IT team had forgotten existed. This dual value — catch the adversary and audit yourself — is why DMARC reporting is one of the highest-leverage controls in this book. The attacker's spoofing and the bank's own misconfiguration show up in the same report, and a good analyst chases both.

Phase 3 — Fix the legitimate senders

Now the unglamorous work that makes enforcement safe. Sam updates the SPF record to include the senders the reports revealed, and works with the HR vendor and the helpdesk provider to enable DKIM so those streams authenticate properly rather than limping:

meridianbank.example.  IN  TXT  "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 ip4:203.0.113.50 include:spf.protection.outlook.example include:_spf.cloud-mail.example include:_spf.helpdesk.example include:_spf.hrvendor.example -all"

The branch scanner gets special handling. Rather than permanently bless an ancient relay, Sam migrates it to send through the authenticated on-prem servers, so it inherits their SPF and DKIM — a small architecture improvement forced by the rollout. He re-checks the reports after each change, confirming that each previously failing "OURS" row flips to pass before he touches the policy. This is the iterative heart of the ladder: change a sender, watch the report, repeat, and do not advance the policy until your own mail is clean.

⚠️ Common Pitfall: Meridian's SPF record is now long, and SPF has a hard limit of 10 DNS lookups during evaluation — each include can trigger more. A record that exceeds it fails with a permerror, silently breaking SPF for all mail. Sam checks the lookup count, flattens where a vendor's include nests too deeply, and removes one provider Meridian no longer uses. The lesson: SPF records rot and bloat; they need periodic pruning, and "add another include" is not free.

Phase 4 — Advance to quarantine, then reject

With every legitimate stream authenticating, Sam advances the policy deliberately, watching reports at each step rather than flipping straight to reject:

Week 5:  p=quarantine; pct=25;  rua=...   (a quarter of failing mail to spam)
Week 6:  p=quarantine; pct=100; rua=...   (all failing mail to spam)
Week 8:  p=reject;     pct=100; rua=...; adkim=s; aspf=s   (failing mail bounced)

The pct ramp at quarantine is a safety valve: if some forgotten legitimate stream surfaces when enforcement begins to bite, only a fraction is affected and the reports reveal it before it becomes a full outage. By week 8, Meridian publishes the enforcing record with strict alignment:

_dmarc.meridianbank.example.  IN  TXT  "v=DMARC1; p=reject; rua=mailto:dmarc-reports@meridianbank.example; ruf=mailto:dmarc-forensic@meridianbank.example; pct=100; adkim=s; aspf=s"

From this moment, any message anywhere on the internet that claims to be from meridianbank.example and fails authentication is rejected by the receiving server before it reaches an inbox. The 300+ daily spoofed messages the team saw in Phase 2 now bounce at the recipient's mail provider. Meridian has made its own name much harder to forge — a control that protects customers it will never meet, enforced by mail servers it does not own, because the standard is global.

Phase 5 — Web hardening and DNS controls alongside

In parallel, Sam applies the §9.5 web baseline to the online-banking portal, because the same attacker who spoofs email also stands up credential-harvesting web pages, and Meridian's own web properties must never be the weak link:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Set-Cookie: session=<id>; Secure; HttpOnly; SameSite=Strict

He submits meridianbank.example to the HSTS preload list (a slow, deliberate step), verifies every header is present on all responses including error pages, and confirms the session cookie carries all three secure attributes. On the DNS side, the team enables DNSSEC signing on Meridian's external zones, turns on validation at the internal resolvers, stands up a threat-intel-fed sinkhole, and ships resolver query logs to the SIEM (Chapter 21) so the §9.6 detections have data to run on.

🔗 Connection: The reporting data from this rollout flows straight into the security-awareness program of Chapter 30. Knowing exactly which look-alike domains and lures target Meridian's people lets Elena's awareness team build realistic phishing simulations and targeted training — and the phish-report button that fed the SOC in Phase 2 becomes a measured metric (report rate) in that program. Machine authentication (this chapter) and human awareness (Chapter 30) are two halves of one anti-phishing defense.

The Outcome

By the end of the quarter, Meridian has moved from "anyone can send mail as the bank" to a state where: its domain spoofing is rejected worldwide; every legitimate internal sender authenticates with SPF and DKIM and aligns under DMARC; the team has a daily, automated feed of anyone attempting to abuse the name; the online-banking portal enforces HTTPS and a sane header baseline; and DNS is signed, validated, sinkholed, and logged. Elena packages this for the board and the next FFIEC exam in one sentence a non-technical director understands: "We publish DMARC at enforcement, so criminals can no longer impersonate the bank by email, and we can prove it." That is a technical control rendered as business risk reduction — the translation skill this book sharpens all the way to Chapter 36.

The project also produced something subtler: a permanent capability. The DMARC reports keep arriving, so any new spoofing campaign or any newly misconfigured internal sender shows up the next day. Email authentication is not a one-time deployment; it is a standing sensor that must be watched — Theme 1, that security is a process, not a product, in concrete form.

Discussion Questions

  1. Sam published SPF with -all (hard fail) on day one, while keeping DMARC at p=none. Explain why this combination is safe, and why "start with ~all and tighten later" usually fails to ever tighten.
  2. The branch scanner relay was discovered only because of the p=none listening phase. What does this say about the relationship between asset inventory and security? Could Meridian have found it another way, and would they have?
  3. Meridian's DMARC reach the 10-lookup SPF limit risk. Discuss the tension between authorizing many third-party senders (each an include) and keeping SPF evaluable. How should an organization decide which senders deserve a place in its SPF record?
  4. The rollout protected customers from being spoofed by mail claiming to be the bank, but did nothing about a customer being phished by a third-party look-alike (as in Chapter 1). Which controls in this chapter address that gap, and why can email authentication alone never close it?
  5. Elena translated the whole project into one board-legible sentence. Practice this skill: write a one-sentence summary of the DNS hardening (DNSSEC + sinkhole + logging) that a non-technical director would understand and care about.

Your Turn

Take a domain you control (or invent a small organization with three to five mail senders). (a) Write the SPF, DKIM-selector, and a p=none DMARC record for it. (b) Sketch what its first DMARC report might show — invent one attacker row and one broken-internal-sender row, and state the action each demands. (c) Write the enforcing p=reject DMARC record you would publish at the end, and the HTTP security-header baseline you would set on its website. (d) In one paragraph, describe the order of your rollout and name the single step where you are most likely to discover a sender you forgot. Keep it to two pages.

Key Takeaways

  • A correct SPF/DKIM/DMARC rollout starts not with a policy but with a listening post (p=none + reporting): you cannot safely enforce until you know which of your own senders currently fail.
  • A DMARC aggregate report is two tools in one: an intrusion feed (who is spoofing you) and a mail-hygiene audit (which of your legitimate streams are broken). A good analyst acts on both.
  • Publish SPF with -all immediately (it is safe while DMARC is p=none); enable DKIM everywhere; then advance DMARC none → quarantine (pct ramp) → reject, fixing your own senders at each step.
  • Watch for SPF's 10-lookup limit and record bloat; every include has a cost, and a permerror silently breaks SPF for all mail.
  • Email authentication eliminates spoofing of your own domain but cannot stop third-party look-alikes — for that you need inbound DMARC verification, the secure email gateway, and human awareness. It is one layer in a defense in depth.
  • The deliverable is not just records in DNS but a standing capability: reports keep arriving, so the control keeps working only if someone keeps watching — security as process, not product.