October 20, 2026
Catching a Lookalike-Domain BEC Email: A Walkthrough of My Open-Source Detection Engine
Upload an email, read the evidence, and see why each rule fired

By Allen Ace
4 min read
Business Email Compromise rarely looks like an attack. This message is titled "Invoice Update." It comes from "Bob Supplier," a contact the recipient already trusts, and the display name is exactly right. Only the address is off:
bob@supplier.com bob@supp1ier.com
The second one swaps the letter l for the digit 1. In a busy inbox, almost nobody will notice.
This walkthrough shows how my open-source BEC detection engine analyzes this message from start to finish, using screenshots from a local run. The email is a synthetic sample built for testing, and no real mail was used.
Step 1: Start the engine
The engine runs as a FastAPI service with PostgreSQL, started with Docker Compose:
docker compose up -d --build
docker compose exec api python -m src.database.init_db
curl http://localhost:8000/healthdocker compose up -d --build
docker compose exec api python -m src.database.init_db
curl http://localhost:8000/health
The API has five endpoints: a health check, a readiness check, a list of past analyses, retrieval of one analysis by ID, and /analyze, which takes an uploaded .eml file and stores the result in PostgreSQL. Every analysis can be retrieved later.
Step 2: Describe what normal looks like
A detection engine cannot call something unusual without knowing what usual is. The request includes a baseline.
For this run I supplied a known domain (supplier.com) and a known display name (Bob Supplier). The form also accepts known participants, known sending hosts, known IP addresses, and a behavioral baseline, all optional.
This is a real design constraint, and I want to state it plainly: right now the caller supplies the baseline. There is no mailbox integration yet, so the engine cannot build it automatically. That is high on my roadmap.
Step 3: Analyze the email
Uploading the file and clicking Execute sends the same request you could make from the command line:
curl -X 'POST' 'http://localhost:8000/analyze' \
-F 'email_file=@supplier-lookalike.eml;type=message/rfc822' \
-F 'known_domain=supplier.com' \
-F 'known_display_name=Bob Supplier' \
-F 'known_behavior={}'curl -X 'POST' 'http://localhost:8000/analyze' \
-F 'email_file=@supplier-lookalike.eml;type=message/rfc822' \
-F 'known_domain=supplier.com' \
-F 'known_display_name=Bob Supplier' \
-F 'known_behavior={}'The server answers with a 200 and a JSON result for each detection rule.
Step 4: Read the evidence
The first rule, BEC-001 (Lookalike Domain), matched with HIGH severity and a risk score of 100. It explains itself with three indicators:
- Display name matches a known participant
- Sender domain differs from the known domain
- Sender domain is visually similar to the known domain
It also returns the evidence it compared: the observed domain supp1ier.com against the known domain supplier.com. An analyst does not have to trust a score. The two strings are right there.
The second rule, BEC-002 (Reply-To Mismatch), did not match, and its score is 0. The reason is in the response: the From address and the Reply-To address are the same lookalike address, bob@supp1ier.com. There is no mismatch to find, so the rule stays quiet. Each rule tests one specific thing, and a rule that stays silent when its condition is absent is the behavior I want.
Step 5: The full picture
The JSON is good for machines. For a human triaging at speed, I format it as a report.
Five of the eight rules matched:
- BEC-001, Lookalike Domain (HIGH, 100): the supp1ier.com domain, as above
- BEC-003, Thread Participant Anomaly (HIGH, 30): a participant who is not in the known conversation
- BEC-004, Authentication Anomaly (HIGH, 30): SPF, DKIM, and DMARC all failed
- BEC-006, Conversation Hijacking (HIGH, 20): the message carries existing thread headers, but the sender is not a known participant
- BEC-007, Behavioral Communication Anomaly (MEDIUM, 20): the message was sent outside historically observed communication hours
Each rule scores independently, and every score is capped at 100. I treat the score as a way to prioritize, not as a verdict. The indicators and evidence are what an analyst should read.
Five independent rules pointing the same way is more convincing than one. A single signal can be a false positive. A lookalike domain, a failed authentication, an unknown participant inside an existing thread, and an odd sending time all at once is a pattern worth stopping.
What an analyst does next
- Hold the message. Do not reply, click, or pay anything.
- Verify the request through a channel you already trust, such as a phone number you already have for the supplier.
- Check the domain's registration age and look for other messages from
supp1ier.comin the mail logs. - Block the domain and search the SIEM for other recipients.
What this example does not prove
I would rather say this than have someone discover it:
- This sample is easy on purpose. The domain is one character off, and all three authentication checks fail. It is a test case, not evidence of real-world accuracy.
- A compromised real mailbox is much harder. In that case the message passes SPF, DKIM, and DMARC and comes from the right domain, so BEC-001 and BEC-004 stay quiet. The behavioral and content rules would have to carry the detection, and those are the least proven.
- I have not yet measured precision, recall, or false-positive rates for the rules on real or labeled data. The thresholds are reasoned defaults, not tuned results.
- Baselines are supplied by the caller, and a poisoned baseline can corrupt what the engine thinks is normal.
- Domain similarity is string-based. It catches the 1-for-l trick. It will not catch every kind of impersonation.
The next steps are a labeled evaluation dataset, published results, and mailbox integration so baselines build themselves.
Try it yourself
The engine is open source and MIT licensed. It has more than 650 automated tests, and the API, database, and SIEM output (Splunk, Elastic, and Wazuh) run from the same Docker setup shown above.
https://github.com/0x0allenace/email-conversation-integrity-detection
If you handle BEC cases in a SOC or at an MSSP, I would like to hear what you see most, what you trust in a detection, and what is missing here.
This project is for defensive security research and authorized testing only. Analyze only email communications you are authorized to inspect.
Contact: Portfolio