Vendor email compromise: the invoice is real, the bank account is not
Vendor impersonation is the most expensive way a company loses money to email, and it is the one fraud where every control you already bought answers a question nobody asked. This is a slow, careful walk through why the callback fails, why account validation misses the point entirely, and what a control that actually works looks like at the endpoint where the damage happens.
An ordinary Tuesday in accounts payable
Picture the AP inbox at a mid-size industrial distributor on a Tuesday morning. Nothing is on fire. The clerk working the queue has been there eleven years and has processed something like forty thousand invoices in that time. She is good at this. She has caught fake invoices before, the obvious ones, the ones with a supplier name spelled slightly wrong and a PDF that looks like it was made in a word processor by someone in a hurry.
At 9:14 an email arrives from a supplier we will call Kellner Fabrication. Kellner has been machining brackets for this distributor since 2019. They invoice on the fifteenth, they get paid net 30, and in six years there has never been a dispute. The email says Kellner has moved its banking to a new institution as part of a treasury consolidation, and asks that remittance details be updated before the next run. Attached is a letter on Kellner letterhead, signed by their controller, with the new routing and account numbers.
Here is what is true about that email. It came from the controller's real address at Kellner's real domain. It is a reply sitting at the bottom of a genuine thread from three weeks ago about a delivery schedule, whole history quoted underneath. It references invoice KF-20418, which is real, open, and due in nine days for $412,000. SPF passes. DKIM passes. DMARC passes. The letterhead is the one on every document Kellner has ever sent, because it was lifted from a document Kellner actually sent.
Everything in that message is true except fourteen digits.
The clerk follows procedure. She calls to verify. Nine days later the payment run goes out, $412,000 lands in an account controlled by someone who has never machined anything, and by the time Kellner calls to ask where their money is, the funds have been moved through three accounts and are gone. We will come back to that phone call, because the phone call is the most interesting part of this story and almost everyone gets it wrong.
Short answer: You cannot verify a vendor bank account change by checking the message, the account, or the payment. Those controls answer different questions. The only control that works requires a named, pre-enrolled human at the supplier to sign the exact new account details from their own device, producing a receipt your ERP stores and your auditor can verify without calling anyone. A compromised mailbox can send the request. It cannot produce the signature.
What is vendor email compromise, and what does it actually cost?
Vendor email compromise is the business email compromise subtype where the attacker impersonates a supplier rather than an executive. Sometimes they own the supplier's mailbox outright. Sometimes they register a lookalike domain and hope nobody counts the letters. Often they sit inside a real thread for weeks, learning the payment cycle, waiting for a large invoice to come due.
The headline number: business email compromise produced $3.05 billion in reported United States losses across 24,768 complaints in 2025, according to the FBI Internet Crime Complaint Center annual report, with roughly 86 percent of that money moving by wire or ACH. Those two rails matter because they are fast and, once the money has moved and been layered, recovery rates fall off a cliff.
The number that should actually worry you is the average. Reported losses work out to roughly $123,005 per complaint. For comparison, the average reported phishing loss in the same dataset is in the low four figures. BEC is not a high volume crime. It is a low volume, high severity crime, and vendor impersonation sits at the expensive end of it, because vendor payments are the largest routine outflows most companies have.
The public cases are the ones with minutes
Private companies rarely disclose. Governments must, because their finances are public record, which is why the clearest examples come from the public sector even though the private sector loses far more in aggregate.
Laurens County, South Carolina wired $1.558 million to criminals impersonating a contractor, on fraudulent wire instructions. The City of Baltimore lost more than $1.5 million in a vendor impersonation scheme uncovered in spring 2025. In both cases the target had accounts payable staff, procedures, and an auditor. In both cases the money left because the change request looked exactly like a change request is supposed to look.
For why this is a board problem rather than an AP problem, do the arithmetic. Annual vendor spend divided by payment runs is roughly the size of one successful incident, if the attacker times it to your largest supplier. At $200 million of vendor spend across 24 runs, one well timed change is worth eight figures to the attacker and a material weakness to your auditor.
Why does the callback fail?
Every AP policy in the world says the same thing: call the vendor to verify, using a known number. This is good advice that fails for three separate reasons, and it is worth being precise about each one, because the failure modes are different and only one of them is fixable by trying harder.
Reason one: the number came from the thread
When the change request arrives, it usually includes a contact number. Sometimes it is in the signature block. Sometimes it is in the letter. Sometimes the attacker updates the vendor record with a new contact number as a separate, boring, unremarkable ticket two weeks before the bank change request, so that by the time anyone calls "the number on file", the number on file is theirs.
The phrase "known number" is doing enormous work there. In practice the known number is whatever the AP system displays, and the AP system displays whatever was entered most recently. If the attacker controls the record, they control the callback. That is not a training failure. It is a design failure: the verification channel and the compromised channel are the same system.
Reason two: caller ID is a suggestion
Suppose the clerk is disciplined and calls the number from the original contract, the one in the procurement file from 2019, not the one in the email. Good. Now she is on a phone network where the calling number is metadata supplied by the originating carrier, and where number spoofing has been cheap and widely available for two decades.
Caller authentication frameworks such as STIR and SHAKEN let carriers attest to a call's origin, and they have helped with some categories of robocall. They do not solve this. Attestation says a carrier vouched for the caller's right to use a number. It says nothing about whether the human speaking is authorized to change a bank account.
Reason three: the voice is no longer evidence
Here is what has changed most in two years. Even if the clerk calls the right number and someone answers, the assumption underneath a callback is that she will recognize a voice, or that a stranger could not convincingly play a controller she has spoken to a dozen times.
Voice cloning from short samples is now a consumer capability. In the contact center world, where this problem is studied closely, industry surveys have found that a large majority of contact center leaders rank synthetic voice as a top threat while a similar majority say they cannot reliably detect it. We wrote about that specific collapse in the contact center piece. The relevant conclusion for AP is simple. A voice on a phone call is no longer a credential. It was always a weak one. It is now approximately zero.
So the callback fails because the number can be poisoned, the caller ID can be forged, and the voice can be synthesized. Three independent failures, and you only need one.
Why doesn't bank account validation stop invoice fraud?
This is the most important misunderstanding in the entire category, so let us take it slowly.
Bank account validation services do something genuinely useful. You send them a routing number, an account number, and a name. They come back and tell you whether the account exists, whether it is open, and in many cases whether the name on the account matches the name you supplied. Banks sell this. NACHA rules around web debit account validation pushed a lot of the market toward adopting it. It is a real control and you should have it.
It is also answering a completely different question from the one you needed answered.
An analogy, and then the precise version
Imagine you are buying a house. Someone emails you and says: the seller has changed solicitors, please send the deposit to this new firm. So you look up the new firm. It exists. It is registered. It has an office, a phone number, a website, and a bank account in its own name. Everything checks out.
You have verified that the destination is real. You have verified nothing about whether the seller asked you to send money there.
That is exactly the gap. Account validation confirms the properties of the destination. Vendor change fraud is not an attack on the destination. It is an attack on the instruction. The attacker is perfectly happy for you to validate the account, because they opened it properly, in a name close enough to pass a fuzzy match, or in the name of a shell entity registered for the purpose. A validated account is not a safe account. It is an account that exists.
Say it in one line and pin it above the AP desk: account validation proves the account. It does not prove the requester.
Name matching helps less than it looks
Sophisticated validation returns a name match score. Surely a mule account in the name "Kellner Fabrication Holdings LLC" would fail against "Kellner Fabrication"?
Sometimes. But consider what AP teams do with a partial match. Legitimate suppliers restructure constantly: holding companies, acquisitions, factored receivables, payments run through a subsidiary with a slightly different registered name. A fuzzy mismatch on a vendor change is a normal Tuesday, not an alarm, and AP teams override them because overriding them is most of the job. The attacker only needs a mismatch of the kind that gets overridden, and they choose the name.
Why don't positive pay and dual approval cover this?
Two more controls that sound like they should apply and do not.
Positive pay guards the instrument, not the master data
Positive pay is a bank service where you send a file listing the payments you intend to make, and the bank refuses anything that does not match. It is genuinely effective against check fraud and against unauthorized payments injected downstream of your system.
Now look at where vendor change fraud happens. The attacker does not forge a payment. The attacker corrupts your vendor master file, and then your systems generate a completely legitimate payment to the corrupted record. That payment appears in your positive pay file, because you did intend to pay Kellner $412,000. The bank matches it and releases it, correctly. Positive pay did its job perfectly and the money is gone, because the fraud was upstream of the instrument.
This is the general shape of the problem. Almost all payment controls sit at the payment. The fraud sits at the master data change, days or weeks earlier, and by the time it reaches the payment it is indistinguishable from legitimate business.
Dual approval is two people reading the same forged email
Dual control is a real principle and it defends against a real threat, which is a single dishonest or careless insider. It defends against nothing here.
When two approvers review a vendor bank change, they are both looking at the same artifact: an email from the supplier's genuine address, with a real invoice reference and a plausible business reason. Both of them ask the same question, get the same answer, and approve. You have not doubled your assurance. You have doubled the number of people who will be in the postmortem.
And when the approvals themselves travel by email or chat, the problem compounds, because now the approval inherits the security of the channel it arrived in. That is a whole failure mode of its own, and we take it apart in the piece on mailbox grade approvals.
The pattern underneath: Mailbox-Grade Approval
Step back and look at the chain as a system, because the individual failures hide the structural one. The supplier's intent to change banks is a fact in the world, and it has to travel from a human at the supplier to a system at the payer. Every control in the standard AP playbook checks the transport: is the email authenticated, is the number right, is the account real, is the payment on the approved list. None of them checks the origin.
We call this Mailbox-Grade Approval: an authorization whose strength is exactly the strength of the channel that carried it, and no more. If the mailbox is compromised, every approval that ever travelled through it is compromised, retroactively and prospectively, and no amount of downstream checking recovers the lost signal.
Once you see the pattern you see it everywhere: the payroll direct deposit change, the wire release, the help desk password reset, the escrow instruction. Different departments, different vendors, same missing primitive.
What would actually stop it?
Invert the question. Instead of asking "how do I tell whether this request is genuine", ask "what could the attacker not produce, no matter how good their email is?"
The answer is a cryptographic signature made by a key held on a device belonging to a specific, named, pre-enrolled human at the supplier, over the exact details being changed.
It is worth sitting with why that differs in kind, not degree, from everything above. The earlier controls all try to assess a request that has already arrived. This one makes an unauthorized request impossible to complete, because completion requires an artifact the attacker cannot forge. No detection model to keep current, no training to refresh. The attacker who owns the supplier's mailbox, reads every thread, clones the controller's voice and answers the callback still cannot sign, because signing needs the private key on the controller's phone.
What exactly gets signed
This is the part people skip, and skipping it is how you end up with a signature that proves nothing. A signature is only as meaningful as the bytes it covers. If the supplier signs "I approve the change", the attacker can replay that signature against a different change. The payload must pin down every fact that matters.
For a vendor bank change, the payload looks like this:
{
"action": "vendor.bank_details.change",
"payer_id": "acme-distribution",
"vendor_id": "KELLNER-0142",
"vendor_legal": "Kellner Fabrication Ltd",
"old_account_hash": "sha256:7f2c9e...a41b",
"new_routing": "021000021",
"new_account": "****3318",
"new_bank_name": "Chase Bank NA",
"effective_date":"2026-09-15",
"requested_by": "[email protected]",
"nonce": "01JQ4Z8XN2",
"issued_at": "2026-09-03T09:41:22Z",
"expires_at": "2026-09-03T10:41:22Z"
}
Four design choices in there are worth explaining, because each one closes a specific attack.
The old account is included as a hash. The signature therefore asserts a transition, from this specific previous account to this specific new one, not merely an endorsement of a new account in the abstract. An attacker who intercepts a signing request cannot re-point it at a different starting state, and a stale signature from an earlier change cannot be replayed after a legitimate change has happened.
The nonce makes it single use. One signature, one change. Capturing the signed blob buys the attacker nothing, because the payer's system will refuse a nonce it has already consumed.
The expiry is short. A signing request that sits unused for an hour dies. This bounds the window in which a signing prompt could be socially engineered onto the wrong person.
The payer is named in the payload. A signature produced for one customer cannot be replayed at another, which matters once suppliers are enrolled across many payers.
The gate, in about a dozen lines
The integration is not the hard part. The vendor master update endpoint refuses to persist without a valid receipt, and the payment run refuses to disburse against a record whose most recent bank change is unsigned. Conceptually:
def update_vendor_bank(req, receipt):
payload = verify_receipt(receipt, MANAV_PUBLIC_KEY) # offline, no callback
assert payload["action"] == "vendor.bank_details.change"
assert payload["payer_id"] == THIS_TENANT
assert payload["vendor_id"] == req.vendor_id
assert payload["new_routing"] == req.new_routing
assert payload["new_account"] == req.new_account
assert payload["old_account_hash"] == sha256(current_account(req.vendor_id))
assert payload["signer_key"] in enrolled_signers(req.vendor_id)
assert not nonce_seen(payload["nonce"])
assert now() < payload["expires_at"]
persist(req) # the change is applied
attach_receipt(req.vendor_id, receipt) # the evidence is filed
consume_nonce(payload["nonce"])
Note what is absent. There is no call to a fraud service, no risk score, no model, and critically no network call to us. verify_receipt checks an Ed25519 signature against a published key. It works on an air gapped machine, it works in five years, and it works if our servers are down. That property matters more than it sounds, and we come back to it when we talk about auditors.
What the vendor actually does
Every control has a human cost, and one the supplier hates gets routed around by your own staff within a quarter. So be concrete.
Kellner's controller gets a notification that a customer has a banking change to confirm. They open it on their phone. The screen shows the facts that matter in plain language: which customer, which vendor record, last four of the old account, last four of the new, effective date. They confirm with the gesture that unlocks the phone. About fifteen seconds.
Nothing is installed. Enrollment happens once through a companion device pairing flow we call Beam: a code shown on one screen is claimed by the phone and bound with an on-device face match and a liveness check. The face never leaves the device, only a one way key remains, so there is no biometric database to breach. The signing half is on the signing demo, and receipt verification is in the developer docs.
Notice what the controller cannot do by accident. They cannot approve a change they did not read, because the change is on the screen they approve. They cannot approve something other than what is displayed, because the signature covers the displayed bytes. That is the principle whose absence makes UI injection attacks so effective, which we cover in the piece on irreversible transfers.
What does each control actually prove?
Here is the whole argument in one table. The right hand column is the one that matters.
| Control | The question it answers | Survives a compromised supplier mailbox? |
|---|---|---|
| SPF, DKIM, DMARC | Did this message come from a server authorized by the domain? | No. The genuine mailbox passes all three. |
| Callback to the number on file | Did someone at a number in our system answer? | No. The record can be poisoned in advance. |
| Callback to a contract number | Did someone at the original number answer and sound right? | Weak. Spoofing and voice cloning both apply. |
| Bank account validation | Does this account exist, is it open, does the name roughly match? | No. The mule account is real and validates. |
| Positive pay | Does this payment match the file we sent the bank? | No. The payment is legitimate; the record is not. |
| Dual approval | Did two of our people look at the same email? | No. Both see identical forged evidence. |
| Signed vendor change | Did a named, enrolled human at the vendor sign these exact new details? | Yes. The mailbox cannot produce the key. |
What does the receipt prove to an auditor or an insurer?
This is where the control stops being a security expense and starts being an audit and insurance asset, which is usually how it gets funded.
Under Sarbanes Oxley, vendor master data is a standard area of control testing, because whoever controls the vendor master controls where money goes. Today an auditor sampling vendor changes gets a log entry saying a user ID modified a record at a timestamp, plus, if you are organized, a scanned letter and a note that someone called someone. That proves your process ran. It does not prove the supplier asked.
A receipt is different in a specific way that auditors care about: it is independently verifiable. The auditor does not have to trust your change log, your AP platform, or us. They take the receipt, they take our published verification key, and they check the signature themselves, offline. If it verifies, a specific enrolled key signed those specific bytes at that specific time. There is no chain of trust to interrogate because there is no chain.
The same property interests crime and cyber underwriters. Social engineering coverage is priced on a control set underwriters cannot verify. Per change evidence, checkable without contacting the vendor or the insured, is a control an underwriter can inspect after a loss. The broader argument about evidence over probability is in the piece on disputes and evidence.
How do you roll this out without enrolling four thousand suppliers?
The honest objection. If this requires every supplier to enroll a human, it is a five year program and nobody will start it. So do not start it that way.
Vendor spend follows a brutal concentration curve. In most companies, somewhere between fifty and two hundred suppliers account for the large majority of disbursed value. The long tail is thousands of vendors receiving amounts too small to be worth an attacker's setup cost. Your exposure is not distributed evenly and your control does not need to be either.
A rollout that works looks like this:
- Rank suppliers by trailing twelve month disbursement. Take the set that covers 80 percent of value. For most mid-market companies that is under a hundred names.
- Enroll one or two named humans at each. Not a role mailbox. A person, usually the controller and a backup, because the failure mode of a single enrolled signer is that they leave and the control gets suspended "temporarily".
- Turn on hard enforcement for that set only. Unsigned change, no change, no exceptions, no override path that AP can invoke under time pressure.
- Apply a value threshold to everyone else. Below the threshold, keep your existing process and accept the residual risk knowingly. Above it, the change waits for enrollment. The threshold is a business decision, and writing it down is itself a control improvement.
- Make enrollment part of onboarding. Every new supplier above the threshold enrolls a signer when they submit a W-9 and their banking details. The marginal cost there is close to zero. Retrofitting is the work, and it is done once.
One second order effect is worth naming. Once Kellner's controller has enrolled for one customer, enrolling for the next costs almost nothing. Suppliers sit at the center of many payer relationships, so every payer who asks for signed changes gets an already enrolled signer for free. That is a two sided network with the shape of card acceptance, and it means the tenth payer to require this has a far easier time than the first.
Honest limits
Here is what this control does not do. Read this section before you buy anything, from us or anyone else.
- Enrollment is the trust bottleneck. Someone, once, has to establish that a keypair belongs to the right human at the supplier. If an attacker owns the mailbox during enrollment, they can enroll themselves. Enrollment should ride an existing high assurance moment: contract signature, an in person meeting, an existing verified relationship. It should never be triggered by an inbound email asking to enroll.
- It does not stop a genuinely dishonest supplier. If Kellner's real controller signs a change to their own fraudulent account, the signature is valid and the money moves. What you get is perfect attribution: a named human cryptographically bound to the instruction. That is a fraud investigation with a defendant rather than a mystery, but it is not prevention.
- It does not cover one time and emergency vendors. The supplier you pay once, urgently, has no enrollment. That is precisely where you should be most suspicious, and it needs a separate procedure.
- Device loss is an operational cost. Controllers lose phones. Enroll at least two signers per supplier so that "our controller got a new phone" never becomes "so we processed it the old way this once". Every exception path you build will eventually be the path the attacker uses.
- There is no ERP connector today. Integration is API first, at the update endpoint. If you want a checkbox in your ERP admin panel, that does not exist yet, and anyone who tells you otherwise is selling a roadmap.
What to do this week
None of the following requires buying anything. Most of it is worth doing even if you never adopt a signature control.
- Pull every vendor bank change from the last 24 months. Count them. Most controllers are surprised: the number is usually in the hundreds, and it is a number nobody tracks.
- For each one, write down the evidence on file. Sort into three buckets: an email only, an email plus a callback logged with a number and a name, or something stronger. If the second bucket is small, you have found your Monday.
- Check whether contact numbers can be edited by the same people who process bank changes. If so, you have the poisoned callback problem structurally, whatever the policy says.
- Compute your single run exposure. Largest supplier, largest single disbursement in the last year. That is the size of one incident. Take that number to whoever signs the budget.
- Write down the value threshold above which a change may not proceed on an email alone. Any number is better than no number, because right now the implicit threshold is infinity.
- Ask your AP platform what identity it records for a vendor change. The answer is almost always "the authenticated session of the user who saved the record", which is the identity of your employee, not of the supplier. That is the gap in one sentence.
- Tell your top ten suppliers you are moving to signed changes. Their AP team has the same problem in the opposite direction, and in our experience they say yes faster than expected.
Frequently asked questions
How do you verify a vendor bank account change request? Require a named, pre-enrolled human at the vendor to sign the exact new account details from their own device, and refuse to persist the change without that receipt. Callbacks can be defeated by poisoned contact records, number spoofing, and voice cloning. Account validation confirms the destination exists but says nothing about who requested the change.
Does bank account validation stop invoice fraud? No. Validation answers whether an account exists, is open, and roughly matches a name. Attackers open real accounts in names designed to pass a fuzzy match, so validation returns a clean result on the mule account. It is a useful control against typos and closed accounts, and it is not a control against a fraudulent change request.
What is vendor email compromise? It is the business email compromise subtype where an attacker impersonates a supplier, usually by taking over the supplier's real mailbox or registering a lookalike domain, then requests that remittance details be updated. The following invoices are genuine and the goods were delivered, so nothing looks wrong until the supplier asks where their money is.
Who is liable when a payment goes to a fraudulent vendor account? Usually the payer, and that is the uncomfortable part. In most jurisdictions the debt to the supplier is not discharged by paying the wrong party, so the payer often has to pay twice. Specific outcomes depend on contract terms, the payment rail, and local law, so treat this as a reason to prevent rather than as legal advice.
Will suppliers actually agree to enroll? The larger ones, generally yes, because they are being impersonated and it damages them too. Start with the suppliers who account for most of your spend, enroll two named people at each, and make enrollment part of onboarding for everyone new. Do not attempt to enroll a four thousand supplier tail on day one.
Does this replace our AP platform or our bank controls? No. It gates one endpoint, the vendor master update, and returns a receipt your systems store. Positive pay, account validation, and approval workflow all continue to do their jobs. This adds the one thing none of them provide, which is proof that the change request came from a specific human at the supplier.
Sources
- FBI Internet Crime Complaint Center, 2025 Internet Crime Report: business email compromise totals, complaint counts, and the wire and ACH share of losses. ic3.gov annual reports
- Laurens County, South Carolina: $1.558 million wired on fraudulent contractor instructions, reported in local coverage and county records.
- City of Baltimore: vendor impersonation loss of more than $1.5 million uncovered in spring 2025, reported in local coverage and city financial disclosures.
- Nacha operating rules on account validation for web debits, which drove much of the market adoption of validation services. nacha.org
- Federal Communications Commission materials on STIR and SHAKEN caller identity attestation and its scope. fcc.gov call authentication
- W3C Web Authentication (WebAuthn) specification, the basis for device bound public key credentials. w3.org WebAuthn
- Uniform Commercial Code Article 4A on funds transfers and loss allocation. Cornell LII, UCC 4A
Account validation proves the account. Only a signature proves the requester, and the requester is the one who moved your money.