From 11b992be89a315c5c34380db92148dafe15889ee Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 10 Oct 2025 13:53:18 -0700 Subject: [PATCH 1/6] New rule: Thread hijacking with typosquat domain Adds a detection rule for vendor impersonation through thread hijacking using typosquat domains. --- .../vendor_impersonation_thread_hijack.yml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 detection-rules/vendor_impersonation_thread_hijack.yml diff --git a/detection-rules/vendor_impersonation_thread_hijack.yml b/detection-rules/vendor_impersonation_thread_hijack.yml new file mode 100644 index 00000000000..dd43960e346 --- /dev/null +++ b/detection-rules/vendor_impersonation_thread_hijack.yml @@ -0,0 +1,41 @@ +name: "Vendor impersonation: Thread hijacking with typosquat domain" +description: "Detects potential thread hijacking where the sender uses a domain similar to known senders, exhibits BEC behavior, and shows signs of compromised thread continuity through domain spoofing or thread manipulation." +type: "rule" +severity: "high" +source: | + type.inbound + and subject.is_reply + // sender domain is close to a known existing sender + and sender.email.domain.root_domain not in $sender_domains + and any($sender_domains, + 0 < strings.ilevenshtein(., sender.email.domain.root_domain) < 3 + ) + and any(ml.nlu_classifier(body.current_thread.text).intents, + .name == "bec" and .confidence != "low" + ) + and 1 of ( + not network.whois(sender.email.domain).found, + any(body.previous_threads, strings.icontains(.preamble, sender.display_name)), + // previous thread sender is a known previous sender, indicating thread hijacking + any(body.previous_threads, + any(regex.iextract(.preamble, '<(?P.*)>'), + strings.parse_email(.named_groups['previous_email']).email in $sender_emails + ) + ), + ) + and ( + profile.by_sender_domain().prevalence == "new" + or profile.by_sender_domain().days_known < 3 + ) + +attack_types: + - "BEC/Fraud" +tactics_and_techniques: + - "Lookalike domain" + - "Social engineering" + - "Spoofing" +detection_methods: + - "Content analysis" + - "Natural Language Understanding" + - "Sender analysis" + - "Whois" From 6cd51e3cbb7a3766d7f93ef9fb6e5dde787bd85e Mon Sep 17 00:00:00 2001 From: ID Generator Date: Fri, 10 Oct 2025 20:55:10 +0000 Subject: [PATCH 2/6] Auto add rule ID --- detection-rules/vendor_impersonation_thread_hijack.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/detection-rules/vendor_impersonation_thread_hijack.yml b/detection-rules/vendor_impersonation_thread_hijack.yml index dd43960e346..d285165e3a3 100644 --- a/detection-rules/vendor_impersonation_thread_hijack.yml +++ b/detection-rules/vendor_impersonation_thread_hijack.yml @@ -39,3 +39,4 @@ detection_methods: - "Natural Language Understanding" - "Sender analysis" - "Whois" +id: "9c2f38ed-dfc3-5251-aaf1-3d35cf18369e" From 439f628c463492c467f597a2d848778b86e03517 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Wed, 15 Oct 2025 13:52:22 -0700 Subject: [PATCH 3/6] Improve negation logic --- .../vendor_impersonation_thread_hijack.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/detection-rules/vendor_impersonation_thread_hijack.yml b/detection-rules/vendor_impersonation_thread_hijack.yml index d285165e3a3..2482abd2a92 100644 --- a/detection-rules/vendor_impersonation_thread_hijack.yml +++ b/detection-rules/vendor_impersonation_thread_hijack.yml @@ -5,8 +5,16 @@ severity: "high" source: | type.inbound and subject.is_reply - // sender domain is close to a known existing sender and sender.email.domain.root_domain not in $sender_domains + // current sender has not been seen in the thread before + and any(body.previous_threads, + length(regex.iextract(.preamble, '<(?P\S*)>')) > 0 + ) + and all(body.previous_threads, + all(regex.iextract(.preamble, '<(?P\S*)>'), + strings.parse_email(.named_groups['previous_email']).email != sender.email.email + ) + ) and any($sender_domains, 0 < strings.ilevenshtein(., sender.email.domain.root_domain) < 3 ) @@ -15,13 +23,7 @@ source: | ) and 1 of ( not network.whois(sender.email.domain).found, - any(body.previous_threads, strings.icontains(.preamble, sender.display_name)), - // previous thread sender is a known previous sender, indicating thread hijacking - any(body.previous_threads, - any(regex.iextract(.preamble, '<(?P.*)>'), - strings.parse_email(.named_groups['previous_email']).email in $sender_emails - ) - ), + any(body.previous_threads, strings.icontains(.preamble, sender.display_name)) ) and ( profile.by_sender_domain().prevalence == "new" From 07fc37e7822dc96f7669096b6420842f8c9360b5 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 17 Oct 2025 09:20:28 -0700 Subject: [PATCH 4/6] Improve org domain checks --- detection-rules/vendor_impersonation_thread_hijack.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/detection-rules/vendor_impersonation_thread_hijack.yml b/detection-rules/vendor_impersonation_thread_hijack.yml index 2482abd2a92..54300b9a413 100644 --- a/detection-rules/vendor_impersonation_thread_hijack.yml +++ b/detection-rules/vendor_impersonation_thread_hijack.yml @@ -9,10 +9,13 @@ source: | // current sender has not been seen in the thread before and any(body.previous_threads, length(regex.iextract(.preamble, '<(?P\S*)>')) > 0 + and any(regex.iextract(.preamble, '<(?P\S*)>'), + strings.parse_email(.named_groups['previous_email']).domain.domain not in $org_domains + ) ) and all(body.previous_threads, all(regex.iextract(.preamble, '<(?P\S*)>'), - strings.parse_email(.named_groups['previous_email']).email != sender.email.email + strings.parse_email(.named_groups['previous_email']).domain.domain != sender.email.domain.domain ) ) and any($sender_domains, From 07f16166bb1abb20194b56462c00f761a52d3680 Mon Sep 17 00:00:00 2001 From: Alex Herold Date: Tue, 28 Oct 2025 07:59:09 -0600 Subject: [PATCH 5/6] Sync .github directory from main branch - Applied .github directory from main to aiden.new.vendorhijack - Ensures workflows and GitHub configurations are up to date - Automated sync via script --- .github/workflows/rule-validate.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rule-validate.yml b/.github/workflows/rule-validate.yml index cdaf2b890a6..428e1c62017 100644 --- a/.github/workflows/rule-validate.yml +++ b/.github/workflows/rule-validate.yml @@ -4,7 +4,9 @@ on: push: branches: [ "main", "test-rules" ] pull_request_target: - branches: [ "**" ] + branches: + - "main" + - 'ci-testing**' workflow_dispatch: {} issue_comment: types: [ created ] From 05ca72f4b71ba4c8bc543ee522ef0e9a62e1448a Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Mon, 3 Nov 2025 14:54:38 -0800 Subject: [PATCH 6/6] Update vendor_impersonation_thread_hijack.yml --- detection-rules/vendor_impersonation_thread_hijack.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/detection-rules/vendor_impersonation_thread_hijack.yml b/detection-rules/vendor_impersonation_thread_hijack.yml index 54300b9a413..f82a191db1e 100644 --- a/detection-rules/vendor_impersonation_thread_hijack.yml +++ b/detection-rules/vendor_impersonation_thread_hijack.yml @@ -24,6 +24,15 @@ source: | and any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec" and .confidence != "low" ) + // risky category + and any(ml.nlu_classifier(body.current_thread.text).topics, + .name in ( + "Financial Communications", + "E-Signature", + "Benefit Enrollment" + ) + and .confidence == "high" + ) and 1 of ( not network.whois(sender.email.domain).found, any(body.previous_threads, strings.icontains(.preamble, sender.display_name))