Is this email trying to trick me?
Most phishing emails give themselves away somewhere: an odd sender domain, a link to a page that only pretends to be your bank, an image that's actually malware. One check rarely catches all of it, so this project runs several and puts the answers side by side.
We built it in 24 hours at a hackathon at SJBIT, as team Axiom, four of us. I built the detection pipeline and the Docker worker that opens links in a sandbox.
The dashboard.
One email, four opinions.
The pipeline signs in to Gmail with OAuth, pulls the newest message in the inbox, and reduces it to plain JSON: sender, subject, date, body, inline image URLs and attachments. Every check reads that same JSON file.
The dangerous part is clicking the link.
Reputation lookups only work for links someone has already reported. To judge a brand-new link you have to load it, and loading an attacker's page on your own machine is exactly what phishing wants. So the visual and image checks run in a separate Docker image, threat_worker, and nothing they touch stays on the host.
Every check is a docker run --rm. Whatever a page drops into the browser is gone when the container exits.
The container can read the email JSON and write to screenshots and results. It can't see the rest of the machine.
Chromium runs as a normal user (uid 1001) inside a slim Python image, never as root.
Who built what.
Most of the commits in the repo are mine. I wrote the end-to-end pipeline, the VirusTotal link and file checks, image extraction in the mail reader, image hashing, the visual check and its Docker worker. My teammates wrote the first mail extractor and VirusTotal link checker, and built the Flask API and the web dashboard.
Honest notes from hour 24.
In the final commit, the web dashboard's API skips VirusTotal (“quota exceeded”) and the Docker checks (“Docker not available”). So the dashboard showed only the sender check, while the link, image and visual checks ran from the command-line pipeline.
The visual verdict is also blunt. It flags any page containing “password”, “login” or “sign in”, which describes every real login page too. Given more time, I'd:
Authentication results say far more about a sender than the display name and subject line do.
Hash the screenshot and compare it with the genuine brand's page. A close match on the wrong domain is the real signal.
A domain registered last week, or one letter off from a bank's, is worth more than a keyword match.