From 24cdef9246db9d341d1a06adefabaa470f0a2cfa Mon Sep 17 00:00:00 2001 From: anti Date: Thu, 30 Apr 2026 11:32:14 -0400 Subject: [PATCH] feat(smtp_relay): ingest probe_forwarded as probe_relay bounty Adds probe_forwarded to meaningful event kinds and stores it in the bounty table as bounty_type=probe_relay with forwarded=true/false, so the dashboard shows whether the upstream actually accepted the test email. --- decnet/correlation/event_kinds.py | 4 ++++ decnet/web/ingester.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/decnet/correlation/event_kinds.py b/decnet/correlation/event_kinds.py index 0af95176..acc7bed1 100644 --- a/decnet/correlation/event_kinds.py +++ b/decnet/correlation/event_kinds.py @@ -41,6 +41,10 @@ INTERACTION_EVENT_TYPES: frozenset[str] = frozenset({ "rcpt_to", "rcpt_denied", "message_accepted", + # probe_forwarded fires when we actually relay the test email upstream + # so the attacker can verify receipt. forwarded=1 means the upstream + # accepted it; forwarded=0 means it failed (but the attacker still got 250). + "probe_forwarded", # File / payload activity "file_captured", "upload", diff --git a/decnet/web/ingester.py b/decnet/web/ingester.py index da686206..7a89e0f5 100644 --- a/decnet/web/ingester.py +++ b/decnet/web/ingester.py @@ -613,6 +613,21 @@ async def _extract_bounty( "content_type": _fields.get("content_type"), }, }) + elif _evt == "probe_forwarded": + # Record whether the upstream relay accepted the probe. forwarded=1 + # means the attacker's test email actually landed in their inbox; + # forwarded=0 means the upstream refused (attacker still got 250). + await repo.add_bounty({ + "decky": log_data.get("decky"), + "service": log_data.get("service"), + "attacker_ip": log_data.get("attacker_ip"), + "bounty_type": "probe_relay", + "payload": { + "msg_id": _fields.get("msg_id"), + "forwarded": _fields.get("forwarded") == "1", + "delivery_count": _fields.get("delivery_count"), + }, + }) # ─── IP-leak detection (XFF / Forwarded / X-Real-IP / CDN variants) ──────────