Ground Truth field notes · defensive security

Home›Email Security›Inbound security

Deep dive + field case · phishing triage

Cleared as safe: a website-form phish that fooled two reviews

A phishing submission came in through a client's website quote form, was cleared as a legitimate sales inquiry, and the error stood for a week until the client caught it. Two reviews had looked at it — an automated assistant and a human analyst — and both missed the threat, for opposite reasons. The envelope was perfect. The attack was entirely in what the visitor typed.

This one is worth writing up because it is a miss, not a win — and because the reason it was missed is structural, not careless. The mail was fully authenticated. It carried no link to click and no file to open. It passed every reputation check a mail filter runs. And it was still phishing. The entire signal lived in one character of a domain the visitor typed into a form field, which is exactly the layer neither review was looking at.

If you only take one idea from this: for relayed form mail, the envelope is trusted and identical every time. The verdict depends entirely on what the visitor typed into the form. Everything below is why that is true, how both reviews went wrong, and the mail-filtering architecture the cleanup exposed underneath.

01How website-form mail actually arrives

The visitor never sends you mail. A relay does, under your own display name, from the vendor's domain.

A company's "Request a Quote" and "Contact Us" forms almost never send mail from the person filling them in. A web vendor's backend collects the submission and relays a notification to the company — sent from the vendor's own domain, under the company's display name, authenticated by the vendor. So the notification looks, at first glance, exactly like display-name spoofing: "Acme Corp" sent from an address that has nothing to do with acme.com. It isn't spoofing. It's how every legitimate form notification arrives.

THE FORM RELAY · ONLY ONE BOX IS ATTACKER-CONTROLLED Visitor types field values: name · company email · phone · text Web vendor backend relays the submission as mail from vendor domain Authenticated send client display name, vendor DKIM/SPF pass DMARC: pass Mailbox lands in Inbox, clean verdict SCL 1 attacker controls only this fixed, authenticated, identical for every submission — genuine or malicious
The whole problem in one picture. A malicious submission and a genuine quote request are indistinguishable by envelope, because the envelope belongs to the vendor, not the visitor. Reputation and authentication checks all pass. The only attacker-controlled bytes are the field values.

02The submission

A polite quote request from a real-sounding vendor — with one character wrong.

The form notification carried the fields exactly as the visitor typed them. Read in isolation it is a bland sales inquiry. Read against the real company it claims to be, every line is a tell. (All values below are fictionalised; the pattern is what matters.)

Form fieldSubmitted valueThe real vendor
Namea plausible buyer name—
CompanyKeystone Bolt & Supply Inc.A real company — same name
Emailbrian.todd@keystonebolts.comReal domain is keystonebolt.com — no trailing s
Phonea toll-free numberDoes not match the vendor's published number
Website (in signature)www.keystonebolt.comThe real site — pasted in to borrow credibility
Messagea vague "business opportunity," asking for the right email address to send a document to—

There are no part numbers, no quantities, no drawings — nothing a real RFQ contains. The only actual request is an email address to send something to. That is the entire payload: this is a first-stage pretext whose job is to get a human to reply, at which point the follow-up carries the malicious document or the credential-harvesting link. The signature even linked the real vendor's website while the From address used a lookalike one character off. That mismatch — real site, fake sender domain — is the signature move of vendor-impersonation phishing.

02bTwo reviews, two misses

One judged the envelope and got it wrong. One judged the body and missed what the fields contained.

The submission was reviewed twice before it was cleared, and the two reviews reached opposite wrong conclusions. An email has layers; each review looked at a different one, and the real threat sat in a layer neither inspected.

THREE LAYERS · THE THREAT WAS IN THE ONE NEITHER CHECKED ① Envelope client display name · vendor domain · DKIM/SPF/DMARC pass · tracking link AUTOMATED REVIEW "bulk platform → spam" ② Body text polite sales message · no link · no attachment · no payment ask ANALYST REVIEW "no payload → legitimate" ③ Submitted field values lookalike sender domain · mismatched phone · vague ask — checked by neither review
Both reviews were competent and both were wrong. The automated pass judged the envelope as a bulk-outreach platform and said "spam, delete." The analyst judged the body as a clean sales note and said "legitimate, route it." The decisive evidence was one layer down, in the field values, and nobody compared them to the real vendor.
Myth

Display name from an unrelated domain = spoofing, treat as spam.

Reality

That is exactly how a legitimate form relay looks. When the vendor's DKIM passes, it is not spoofing. Acting on "spam" would have blocked the client's own lead intake.

Myth

No link and no attachment means there's no phishing here.

Reality

The absence of a payload is normal for a first-stage pretext. The attack depends on the reply, not on a click. The harm arrives in the follow-up.

Myth

Two automated notes disagree, so pick the one that sounds right.

Reality

Contradictory triage notes are a signal to reconcile, not to choose. The disagreement itself meant nobody had actually identified what the message was.

03Why the envelope could never help

Every sample of this relay's mail authenticates perfectly and filters as clean. That is the point.

Pulling raw headers from several of the vendor's real notifications made the trap explicit: all of them pass SPF, DKIM, DMARC and composite authentication, and all of them are scored as clean, non-spam mail delivered to the Inbox. There is no envelope signal that separates a malicious submission from a genuine one, because the envelope is the vendor's and the vendor is legitimate.

Header signalWhat every sample showed
SPF / DKIM / DMARCAll pass, aligned to the vendor's domain
Composite auth (CompAuth)pass, reason 100
Sending IPsSeveral different IPs across two countries — an IP allow-list would break; the DKIM domain is the only stable identifier
Spam verdictSFV:NSPM — went through full filtering and was judged not spam
AttachmentsSome form types pass uploaded files through, so malware and Safe Attachments scanning must keep applying

Read the verdict, not just the pass/fail

SFV:NSPM means "filtered normally, judged clean." If an allow-list in the applied policy had bypassed filtering, you'd see SFV:SKA instead. Spotting NSPM where you expected SKA was the first clue that the allow entry everyone assumed was protecting this mail wasn't being applied at all — which opened up the whole policy-scoping problem below.

04The investigation, and the trap underneath

Nothing was blocking the vendor's mail. But the reason that was true turned out to be luck, not design.

The first job was to disprove the automated review's claim that the vendor's mail was being treated as spam. A handful of read-only checks in Exchange Online PowerShell settled it — nothing was quarantining or blocking the relay — but check #7 is where it got interesting.

# Is the vendor's mail being quarantined? (30 days)
Get-QuarantineMessage -SenderAddress info@webvendor.example `
  -StartReceivedDate (Get-Date).AddDays(-30) |
  Select ReceivedTime, RecipientAddress, Subject, QuarantineTypes
# → no messages

# Is it on the Tenant Allow/Block List?
Get-TenantAllowBlockListItems -ListType Sender | ? Value -like "*webvendor*"
# → no entries

# Is it referenced in any anti-spam policy?
Get-HostedContentFilterPolicy |
  Select Name, AllowedSenderDomains, BlockedSenderDomains |
  ? { ($_ | Out-String) -match "webvendor" }
# → found in the DEFAULT policy's allowed domains

So the vendor's domain was on an allow-list — in the Default anti-spam policy. The problem: the headers said that allow was never applied (NSPM, not SKA). That contradiction only resolves one way: the Default policy does not cover these mailboxes.

WHICH RECIPIENT FALLS TO WHICH POLICY Custom policy scope: primary domain, priority 0 covers: user@company.com allow/block lists here protect ONLY the primary domain (one mailbox excepted → falls to Default) Default (catch-all) everything no custom rule matched secondary domains · onmicrosoft the big allow/block lists people kept adding here protect almost nobody Tenant Allow/Block List applies to every recipient in every accepted domain, whichever policy covers them
The scoping trap. A custom policy, created years earlier and scoped to the whole primary domain, was the effective policy for nearly every mailbox. All the allow and block entries accumulated in Default protected only the handful of addresses on secondary domains. The Tenant Allow/Block List is the one place that sidesteps the whole question.

The mechanism, in plain terms: Exchange Online matches each recipient address (not the user) against enabled custom policy rules in priority order; the first match wins; anything unmatched falls to Default. Here a long-forgotten custom policy — named after a single vendor someone wanted to block years ago, then scoped to the entire domain — quietly became the real policy for almost everyone. So:

A "missing cmdlet" usually means missing rights

The first attempt to add the block failed with New-TenantAllowBlockListItems is not recognized. Exchange Online only imports the cmdlets your session's roles permit, so a read-only role surfaces as a missing cmdlet rather than an access-denied error. Get-Command *TenantAllowBlockListItems* showed only the Get- verb loaded. Reconnecting with a write-capable role fixed it.

05The fix

Block the lookalike tenant-wide; protect the real relay with an authentication-conditioned rule.

Two changes, both designed to be immune to the scoping trap above. The block goes in the Tenant Allow/Block List so it covers every recipient regardless of policy. The allow is a transport rule that only fires when the vendor's own DKIM validates — so a forged From address gets no free pass, and malware/Safe Attachments scanning still applies.

# 1 — block the lookalike domain for the whole tenant, no expiry
New-TenantAllowBlockListItems -ListType Sender -Block `
  -Entries "keystonebolts.com" -NoExpiration `
  -Notes "lookalike of keystonebolt.com (website-form pretext)"

# 2 — guarantee the real form relay is never quarantined,
#     but ONLY when the vendor's DKIM actually passes
New-TransportRule -Name "Allow web form relay (DKIM pass)" `
  -From "info@webvendor.example" `
  -HeaderMatchesMessageHeader "Authentication-Results" `
  -HeaderMatchesPatterns "dkim=pass[^;]*header\.d=webvendor\.example" `
  -SetSCL -1 `
  -Comments "website form submissions must never be quarantined" `
  -Priority 0

The block does double duty: it stops the attacker's follow-up mail — the second-stage message sent directly from the lookalike domain, which is where the actual payload would arrive — and, per Microsoft's docs, a sender/domain block also stops users sending to that domain (worth a test send to confirm). The transport rule's DKIM condition is the important bit: an unconditioned "allow this sender" rule is itself a spoofing hole.

The one-line model

Put sender allows and blocks in the Tenant Allow/Block List, not inside an anti-spam policy — policy lists silently depend on policy scoping. And never allow a relay by address alone; condition it on the relay's own DKIM, or you've built the spoofing bypass yourself.

06Triage checklist for relayed form mail

When the envelope is trusted and identical every time, the verdict lives entirely in the fields.

  1. Confirm it's the real relay. Expected From address, expected Message-Id domain, DKIM pass for the vendor. If authentication fails, you're looking at spoofing of the relay itself — a different problem.
  2. Identify the form from the subject (quote request vs contact-us). They behave differently on reply.
  3. Extract the submitted email domain, phone and website.
  4. Look up the claimed company independently and compare its real domain and phone against the submitted values — character by character. A one-character domain difference is decisive.
  5. Check the submitted domain's age and whether it hosts a real site.
  6. Read the request. Real quote requests name parts, quantities, materials, drawings. A vague "business opportunity" whose only ask is an email address is a pretext.
  7. For submissions with attachments, confirm Safe Attachments scanned them before advising anyone.
  8. For contact-us forms, warn that Reply goes straight to the submitted address — lookalike domains included.
  9. If any indicator fails, block the submitted domain in the Tenant Allow/Block List and run a message trace for any outbound replies.
# did anyone reply to the lookalike before the block went in?
Get-MessageTraceV2 -RecipientAddress "*@keystonebolts.com" `
  -StartDate (Get-Date).AddDays(-10) -EndDate (Get-Date) |
  Select Received, SenderAddress, RecipientAddress, Subject, Status
  • Symptom: a clean, fully authenticated website-form notification cleared as a legitimate sales inquiry.
  • Root cause: the sender's email domain was a one-character lookalike of a real vendor's — a first-stage pretext with no payload, invisible to envelope and body checks alike.
  • Both reviews missed it: the automated pass judged the envelope ("bulk platform → spam"), the analyst judged the body ("no payload → legitimate"); neither compared the field values to the real vendor.
  • Exposed underneath: a forgotten custom anti-spam policy scoped to the whole domain meant the allow/block lists in Default protected almost nobody.
  • Fix: block the lookalike in the Tenant Allow/Block List; allow the real relay with a DKIM-conditioned transport rule; move sender allows/blocks out of policy lists.

Sources & further reading

Anonymised from real support work. Client, vendor, domain, person and ticket details have been changed; the mechanism and the mistake are real.

Filed under
Email Security › Inbound security
Browse this part of the knowledge base.
Related

Comments

Questions or corrections welcome. Sign in with GitHub to join the thread.