From aac98085bffca102d835d3a5d9ab7c862ba2f9d0 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:52:35 -0500 Subject: [PATCH 01/12] Create vip_impersonation_fake_thread_with_invoice_handoff.yml --- ...ation_fake_thread_with_invoice_handoff.yml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml new file mode 100644 index 00000000000..dd21b769817 --- /dev/null +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -0,0 +1,74 @@ +name: "VIP impersonation: VIP payment redirect handoff via thread hijacking" +description: "Detects inbound messages where an external sender, absent from the original conversation, targets a single internal recipient after a VIP previously instructed that party to handle invoice or payment correspondence. The rule identifies prior threads where a known VIP explicitly redirected billing or payment contact to an internal address — using language such as forwarding instructions, accounts payable references, or billing handoff phrasing — and flags follow-up messages from external senders who are no longer accompanied by the VIP. NLU classifiers confirm financial context in the prior thread. This pattern is consistent with adversaries monitoring or fabricating invoice-related threads to insert themselves at the point of payment handoff." +type: "rule" +severity: "high" +source: | + type.inbound + and any(map(filter(body.previous_threads, + any($org_vips, + strings.icontains(..sender.display_name, .display_name) + and strings.icontains(..sender.email.email, .email) + ) + // remove threads that are auto replies (VIP is out of office and instructs the sender to sent another email address) + and not .subject.is_auto_reply + // the recipient of the current message is the one mentioned by the VIP + and any(recipients.to, + .email.email != ..sender.email.email + and .email.domain.root_domain in $org_domains + and strings.icontains(..text, .email.email) + ) + // the "handoff" phrases + and regex.icontains(.text, + 'accounts? payable', + '(?:forward|send|rout|direct|remit|submit|issue) it (?:directly )?to', + '(?:forward|send|direct|remit|submit|route) (?:the |all |related )?(?:invoice|correspondence|payment|billing)', + 'for payment processing,? please contact', + '(?:please )?direct (?:it|all|the)[^\n]{0,60}\bto\b', + '(?:contact|reach out to)[^\n]{0,40}\bat\b[^\n]{0,40}@', + '(as follows|provided below|find below|details are|contact is)[^\n]{0,10}:', + 'billing (?:contact|correspondence|team|department)' + ) + // NLU has mentions of invoices/finance/etc + and ( + any(ml.nlu_classifier(.text, subject=.subject.base).topics, + ( + .name == "Financial Communications" + or .name == "Request to View Invoice" + ) + and .confidence != "low" + ) + or any(ml.nlu_classifier(.text, subject=.subject.base).tags, + (.name == "invoice" or .name == "payment") + and .confidence != "low" + ) + or any(ml.nlu_classifier(.text, subject=.subject.base).entities, + .name == "financial" + ) + ) + ), + .sender.email.email + ), + . != "" + // the VIP is no longer in the message + and not strings.icontains(sender.email.email, .) + and not any(flatten([recipients.to, recipients.cc, recipients.bcc]), + strings.icontains(.email.email, ..) + ) + ) + // only a single org_domain recipient + and length(filter(flatten([recipients.to, recipients.cc, recipients.bcc]), + .email.domain.root_domain in $org_domains + ) + ) == 1 + // sender is external + and not sender.email.domain.root_domain in $org_domains +attack_types: + - "BEC/Fraud" +tactics_and_techniques: + - "Impersonation: VIP" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Natural Language Understanding" + - "Sender analysis" + - "Header analysis" From 0e745609642e740573d67bcaa1742f6c62f52c72 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Mon, 6 Jul 2026 21:56:01 +0000 Subject: [PATCH 02/12] Auto-format MQL and add rule IDs --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index dd21b769817..e5433c80f62 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -72,3 +72,4 @@ detection_methods: - "Natural Language Understanding" - "Sender analysis" - "Header analysis" +id: "215b8849-c7b5-577c-844f-be0e0dfc9116" From 02a153e0c4441b9e72e69fadf92518039ce5e615 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:16:03 -0500 Subject: [PATCH 03/12] avoid the nits --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index e5433c80f62..7de89122005 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -25,7 +25,7 @@ source: | 'for payment processing,? please contact', '(?:please )?direct (?:it|all|the)[^\n]{0,60}\bto\b', '(?:contact|reach out to)[^\n]{0,40}\bat\b[^\n]{0,40}@', - '(as follows|provided below|find below|details are|contact is)[^\n]{0,10}:', + '(?:as follows|provided below|find below|details are|contact is)[^\n]{0,10}:', 'billing (?:contact|correspondence|team|department)' ) // NLU has mentions of invoices/finance/etc From 2060807b659acb73e9cc64e7c405956e74696a61 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:12:31 -0500 Subject: [PATCH 04/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 7de89122005..1eb060d2dd4 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -10,7 +10,8 @@ source: | and strings.icontains(..sender.email.email, .email) ) // remove threads that are auto replies (VIP is out of office and instructs the sender to sent another email address) - and not .subject.is_auto_reply + // accounting for threads that don't have a subject + and not coalesce(.subject.is_auto_reply, false // the recipient of the current message is the one mentioned by the VIP and any(recipients.to, .email.email != ..sender.email.email From 96dc61e0b62dea23f943a979b7913e3d26c2b113 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:13:49 -0500 Subject: [PATCH 05/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 1eb060d2dd4..7c949c7bdc6 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -11,7 +11,7 @@ source: | ) // remove threads that are auto replies (VIP is out of office and instructs the sender to sent another email address) // accounting for threads that don't have a subject - and not coalesce(.subject.is_auto_reply, false + and not coalesce(.subject.is_auto_reply, false) // the recipient of the current message is the one mentioned by the VIP and any(recipients.to, .email.email != ..sender.email.email @@ -63,6 +63,7 @@ source: | ) == 1 // sender is external and not sender.email.domain.root_domain in $org_domains + attack_types: - "BEC/Fraud" tactics_and_techniques: From d059be8a4c8cc4d3d34f2ea680ede4e9b07f444d Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 7 Jul 2026 09:08:02 -0500 Subject: [PATCH 06/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 7c949c7bdc6..b3b5d286ece 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -7,7 +7,10 @@ source: | and any(map(filter(body.previous_threads, any($org_vips, strings.icontains(..sender.display_name, .display_name) - and strings.icontains(..sender.email.email, .email) + or ( + .email != "" + and strings.icontains(..sender.email.email, .email) + ) ) // remove threads that are auto replies (VIP is out of office and instructs the sender to sent another email address) // accounting for threads that don't have a subject From 85f1911af135af3c971e7ec5d314f367488e336d Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:54:41 -0500 Subject: [PATCH 07/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index b3b5d286ece..30eb7e0cf79 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -1,4 +1,4 @@ -name: "VIP impersonation: VIP payment redirect handoff via thread hijacking" +name: "VIP impersonation: VIP payment redirect handoff via fake threads" description: "Detects inbound messages where an external sender, absent from the original conversation, targets a single internal recipient after a VIP previously instructed that party to handle invoice or payment correspondence. The rule identifies prior threads where a known VIP explicitly redirected billing or payment contact to an internal address — using language such as forwarding instructions, accounts payable references, or billing handoff phrasing — and flags follow-up messages from external senders who are no longer accompanied by the VIP. NLU classifiers confirm financial context in the prior thread. This pattern is consistent with adversaries monitoring or fabricating invoice-related threads to insert themselves at the point of payment handoff." type: "rule" severity: "high" From 55166eab26fc39b606baa382ee41a2b599c8c6d3 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:57:52 -0500 Subject: [PATCH 08/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- ...ation_fake_thread_with_invoice_handoff.yml | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 30eb7e0cf79..6d3e17a7bdd 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -5,6 +5,8 @@ severity: "high" source: | type.inbound and any(map(filter(body.previous_threads, + // VIP authored the segment: display_name OR real email (OR, not AND -- the actor guesses + // the exec's address, so a fabricated From: is often the wrong format at the right org). any($org_vips, strings.icontains(..sender.display_name, .display_name) or ( @@ -12,16 +14,15 @@ source: | and strings.icontains(..sender.email.email, .email) ) ) - // remove threads that are auto replies (VIP is out of office and instructs the sender to sent another email address) - // accounting for threads that don't have a subject + // skip auto-replies; coalesce the null on subject-less segments before `not`. and not coalesce(.subject.is_auto_reply, false) - // the recipient of the current message is the one mentioned by the VIP + // the live recipient is the payee the VIP names, at an org domain. and any(recipients.to, .email.email != ..sender.email.email and .email.domain.root_domain in $org_domains and strings.icontains(..text, .email.email) ) - // the "handoff" phrases + // payment "handoff" phrasing. and regex.icontains(.text, 'accounts? payable', '(?:forward|send|rout|direct|remit|submit|issue) it (?:directly )?to', @@ -32,42 +33,34 @@ source: | '(?:as follows|provided below|find below|details are|contact is)[^\n]{0,10}:', 'billing (?:contact|correspondence|team|department)' ) - // NLU has mentions of invoices/finance/etc - and ( - any(ml.nlu_classifier(.text, subject=.subject.base).topics, - ( - .name == "Financial Communications" - or .name == "Request to View Invoice" - ) - and .confidence != "low" - ) - or any(ml.nlu_classifier(.text, subject=.subject.base).tags, - (.name == "invoice" or .name == "payment") - and .confidence != "low" - ) - or any(ml.nlu_classifier(.text, subject=.subject.base).entities, - .name == "financial" - ) - ) ), .sender.email.email ), . != "" - // the VIP is no longer in the message + // the VIP is no longer present in the live message. and not strings.icontains(sender.email.email, .) and not any(flatten([recipients.to, recipients.cc, recipients.bcc]), strings.icontains(.email.email, ..) ) + // any previous thread authored by the "VIP" has invoice/payment/ + and any(filter(body.previous_threads, .sender.email.email == ..), + any(ml.nlu_classifier(.text, subject=.subject.base).tags, + .name in ("invoice", "payment") + and .confidence != "low" + ) + or any(ml.nlu_classifier(.text, subject=.subject.base).topics, + .name in ("Request to View Invoice", "Payment Information") + and .confidence != "low" + ) + ) ) - // only a single org_domain recipient + // exactly one org-domain recipient (the payee); external sender. and length(filter(flatten([recipients.to, recipients.cc, recipients.bcc]), .email.domain.root_domain in $org_domains ) ) == 1 - // sender is external and not sender.email.domain.root_domain in $org_domains - -attack_types: + attack_types: - "BEC/Fraud" tactics_and_techniques: - "Impersonation: VIP" From a1906c2e3e4e00dda4990901da6fb8c2f981ff5c Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:08:49 -0500 Subject: [PATCH 09/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 6d3e17a7bdd..2150fa71384 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -60,7 +60,7 @@ source: | ) ) == 1 and not sender.email.domain.root_domain in $org_domains - attack_types: +attack_types: - "BEC/Fraud" tactics_and_techniques: - "Impersonation: VIP" From 80d3059ca83ef11a6bd39ad23a10d1c1ee48f33f Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 7 Jul 2026 21:10:04 +0000 Subject: [PATCH 10/12] Auto-format MQL and add rule IDs --- ...vip_impersonation_fake_thread_with_invoice_handoff.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 2150fa71384..bb86d8eca48 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -45,11 +45,13 @@ source: | // any previous thread authored by the "VIP" has invoice/payment/ and any(filter(body.previous_threads, .sender.email.email == ..), any(ml.nlu_classifier(.text, subject=.subject.base).tags, - .name in ("invoice", "payment") - and .confidence != "low" + .name in ("invoice", "payment") and .confidence != "low" ) or any(ml.nlu_classifier(.text, subject=.subject.base).topics, - .name in ("Request to View Invoice", "Payment Information") + .name in ( + "Request to View Invoice", + "Payment Information" + ) and .confidence != "low" ) ) From 757e3f44927478a75f815514ecc8c76ba00795ce Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:47:53 -0500 Subject: [PATCH 11/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index bb86d8eca48..9e49685c155 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -29,7 +29,6 @@ source: | '(?:forward|send|direct|remit|submit|route) (?:the |all |related )?(?:invoice|correspondence|payment|billing)', 'for payment processing,? please contact', '(?:please )?direct (?:it|all|the)[^\n]{0,60}\bto\b', - '(?:contact|reach out to)[^\n]{0,40}\bat\b[^\n]{0,40}@', '(?:as follows|provided below|find below|details are|contact is)[^\n]{0,10}:', 'billing (?:contact|correspondence|team|department)' ) From 18edc011263898ca9cd83faab0a3ee4f264be996 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:25:07 -0500 Subject: [PATCH 12/12] Update vip_impersonation_fake_thread_with_invoice_handoff.yml --- .../vip_impersonation_fake_thread_with_invoice_handoff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml index 9e49685c155..2585359b916 100644 --- a/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml +++ b/detection-rules/vip_impersonation_fake_thread_with_invoice_handoff.yml @@ -41,7 +41,7 @@ source: | and not any(flatten([recipients.to, recipients.cc, recipients.bcc]), strings.icontains(.email.email, ..) ) - // any previous thread authored by the "VIP" has invoice/payment/ + // any previous thread authored by the "VIP" has invoice/payment and any(filter(body.previous_threads, .sender.email.email == ..), any(ml.nlu_classifier(.text, subject=.subject.base).tags, .name in ("invoice", "payment") and .confidence != "low"