feat: per-mailbox sender-graph BEC detector (closes #26)#301
Open
schmug wants to merge 1 commit into
Open
Conversation
Adds a `sender_graph` table to the per-mailbox SQLite DO tracking (display_name, sender_address) pairs. The `SenderGraphDetector` flags BEC-style impersonation when a new address claims a display name already seen from different addresses in that mailbox, scoring +10–25 (capped at +30). The boost is applied as a post-aggregation step in the verdict stage alongside the existing intel-feed and off-hours boosts. Per-mailbox `detectors.sender_graph.enabled` setting (default: true) lets operators disable the signal. Fresh mailboxes produce 0 contribution until sender history accumulates, so there are no false positives on first use. https://claude.ai/code/session_01BDrRMH9q5V7G3V1ruLns6J
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ais-hub | 4ffc977 | Commit Preview URL Branch Preview URL |
May 19 2026, 12:27 PM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sender_graphSQLite table to the per-mailbox Durable Object tracking(display_name, sender_address)history, seeded on every inbound email.Detectorinterface (workers/security/detectors.ts) andSenderGraphDetectorimplementing BEC / display-name impersonation detection: flags when a new sender address claims a display name previously seen from a different address in that mailbox.detectors.sender_graph.enabledtoMailboxSecuritySettings(default:true); setting tofalsedisables the signal and returns scoring to baseline.Closes #26
Authz / false-positive design
Fresh mailboxes produce zero detector contribution — the table starts empty, so there is no history to trigger on. The +30 cap and the graduated scoring (1 message → +10, 2–4 → +15, ≥5 → +25) ensure the detector can only tilt borderline verdicts until the mailbox has built real sender history.
Size note
9 files touched, ~480 lines. All 9 files are tightly coupled to deliver a single atomic feature (schema → migration → DO methods → detector → settings → pipeline integration → tests). They cannot be split into two independently useful PRs.
Test plan
npm testpasses — 1092 tests (84 files), including 13 new tests intest/security/sender-graph-detector.test.tsnpm run typecheckpasses — 0 errorsBEC signalin verdict signalsdetectors.sender_graph.enabled: false→ no BEC signal regardless of historyupsertSenderGraphcalled after pipeline run (sender graph updated on every inbound)Math.min(30, result.score))Acceptance shipped
Detectorinterface for pluggable future detectorsSenderGraphDetectorBEC signaldetectors.sender_graph.enabled)Acceptance deferred
detectors.sender_graph.enabledknob (the setting is writable via the settings API; a dedicated UI surface is a follow-up)Spec follow-up needed
No — this feature adds a new scoring component and does not change or contradict any existing rule in SECURITY_SPEC.md.
https://claude.ai/code/session_01BDrRMH9q5V7G3V1ruLns6J
Generated by Claude Code