John Jomi
All Projects
In Development/Case Study

Tycoon 2FA — AiTM Phishing Detection

A research prototype that detects Tycoon 2FA and other adversary-in-the-middle phishing email. It reads raw RFC-822 messages from a Gmail mailbox in read-only mode, runs them through four independent detection layers, and combines the result into a single composite risk score with a deliver, warn or block verdict.

This is a research prototype at repository-bootstrap stage. The architecture, data contracts and scoring design are specified in full and core/models.py is implemented, but the detection layers themselves are not yet built — there are no measured results to report and no detection capability to claim. It is read-only and takes no remediation action.

The Problem

Adversary-in-the-middle phishing kits defeat multi-factor authentication by proxying the real login page in real time, so the victim's second factor is captured along with their password. The messages that deliver these kits are engineered to survive conventional filters: the payload URL hides behind redirect chains, CAPTCHA gates and QR codes, and the body is obfuscated well enough to pass keyword matching. A verdict from such a filter is also a bare number, which is useless to an analyst who has to justify why a message was blocked.

Detection layers

Four layers examine the message independently, each emitting signals with human-readable evidence rather than an opaque score. Because no layer is authoritative on its own, a message that looks clean to one can still be caught by another.

LayerFocus
L1 — Header & domain intelligenceAuthentication results, Reply-To mismatch, domain age, display-name impersonation
L2 — URL & redirect chainRedirect depth, base64-encoded email parameters, CAPTCHA gating, QR-embedded URLs
L3 — NLP / ML body analysisUnicode obfuscation, urgency classification, perplexity and burstiness
L4 — Threat intelligenceURL and domain IOC lookups, hosting reputation correlation

Explainability as a hard requirement

Every signal is a frozen DetectionSignal record carrying its layer, a layer-local name, a normalized 0–1 score, a severity, and an evidence string that is validated non-empty. The evidence is the point: a bare score demonstrates nothing to the analyst reading the verdict, so the UI renders those strings directly. A signal records what was observed and is never edited afterwards.

  • One generic signal model shared by all four layers, with no per-layer subclasses
  • Qualified names such as L2/redirect_depth identify a signal's origin
  • An error field records signals that could not be computed, rather than silently dropping them
  • Generic grouping and filtering by layer is what makes the planned ablation study possible

Scoring design

Weights live in configuration, never on the signals themselves and never hardcoded. A signal is an observation; how much that observation counts toward the composite is a policy decision owned by the scoring module. Keeping the two separate means refitting the model changes one YAML file rather than every layer, and the same recorded signals can be rescored under different weightings.

  • Phase A uses hand-assigned weights — L1 0.30, L2 0.30, L3 0.20, L4 0.20
  • Phase B fits a logistic regression over the full signal vector on a labelled corpus
  • Thresholds are re-derived from the ROC curve rather than guessed
  • The operating point weights false positives more heavily than false negatives — a blocked legitimate invoice is a business incident, a missed phish is one more item for the next control

Risk and action are separate stages

The system keeps two vocabularies deliberately distinct. Composite scoring produces a risk level — low, medium or high — answering how risky a message is. A separate policy stage maps that classification onto an operational action of deliver, warn or block, answering what should be done about it. The mapping is a deployment policy, not a property of the message, so the two are never conflated.

Ingest

Messages are pulled from Gmail strictly read-only. Nothing is moved, labelled, quarantined or deleted, and the prototype is not publicly deployed. Design goals throughout are defensibility and reproducibility — every claim the README makes is intended to be backed by a measurement the evaluation harness produces.