Most phishing advice stops at "be careful." That's not very useful when an
email looks pixel-perfect identical to your bank's. I wanted something that
points at the actual line and says: this is the problem, and here's why.
So I built Kanca — an open-source tool that reads the raw source of an
email the way a security person would: who really sent it, which servers it
passed through, where the links actually go, what's in the attachments. It
marks every suspicious part directly on the source and explains why it
matters.
🔗 Live: https://kanca.kadirify.com/
🔗 Repo: https://github.com/Kadirify/kanca
The two constraints that shaped everything
No AI. The score comes from 50 rules anyone can read in the repo. Same
email in, same result out, every time. No model drift, no "the API changed
its mind," no black box.
Nothing leaves the browser. The email you paste is parsed, matched
against rules, and scored entirely client-side. The one optional exception
is a DNS lookup (SPF/DMARC/MX) on the sender's domain — and even then, only
the bare domain goes out, never anything from the email itself.
Making the same code run in three places
I wanted the exact same analysis logic to run in the browser, in a Node CLI
(for testing against sample emails), and in the test suite — no duplicated
logic, no "works in browser but not in tests."
The trick: isolate the two environment-specific pieces — HTML parsing and
DNS resolution — behind interfaces, and inject the real implementation at
the entry point.
\
@kanca/engine/browser → DOMParser + fetch-based DNS resolver
@kanca/engine/node → cheerio + node:dns
\\
Everything else — MIME parsing, the 50 rules, brand-lookalike matching with
Levenshtein distance, the scoring logic — is plain TypeScript with zero
environment assumptions.
Scoring, briefly
Each triggered rule adds its weight. Repeats of the same rule only add 25%
of the weight each time (so one spammy pattern repeated 10 times doesn't
dominate the score). Each layer (headers, DNS, domain, links, attachments,
content) has a cap, so no single weak signal can push a score to "high risk"
on its own. +5 bonus if three or more layers have findings. Capped at 100.
Stack
- pnpm monorepo, TypeScript, ESM
- postal-mime for MIME parsing, tldts for domain parsing
- React 19 + Vite 6 on the frontend
- Hono for the one API route (DNS lookups only)
- Vitest for tests
- Deployed on Vercel
Try it
https://kanca.kadirify.com/ — paste a suspicious email (or try one of the
built-in samples) and see what it finds. English and Turkish UI.
Open to feedback, especially on rules that feel off or phishing patterns
I'm missing. It's MIT licensed and actively maintained.



Top comments (0)