From 1b8a0e2954a7b0acf5c081a7cace760debf22f31 Mon Sep 17 00:00:00 2001 From: Jonathan Katzman Date: Mon, 6 Jul 2026 10:33:24 -0400 Subject: [PATCH 1/4] Match blue-button style via xpath predicate instead of regex over full anchor subtree regex.icontains(.raw, ...) scanned each anchor's entire rendered subtree (all descendant markup), so cost scaled with how much content each button wrapped rather than link count. This caused a very slow live evaluation on a message with content-heavy anchors. Checking the anchor's own @style attribute via an xpath predicate avoids scanning descendants entirely. --- .../phishing_blue_button_file_sharing.yml | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/detection-rules/phishing_blue_button_file_sharing.yml b/detection-rules/phishing_blue_button_file_sharing.yml index 8e26a348b57..772149d9f18 100644 --- a/detection-rules/phishing_blue_button_file_sharing.yml +++ b/detection-rules/phishing_blue_button_file_sharing.yml @@ -17,42 +17,38 @@ source: | ) ) ) - and any(filter(html.xpath(body.html, '//a[@href]').nodes, - // blue button background, background-color and observed colors - regex.icontains(.raw, - '(?:background(?:-color)?)\s*[:\s]\s*#(?:0078d4|3a78d1)' - ) - ), - ( - // it's styled as a button - regex.icontains(.raw, 'padding') - ) + and any(html.xpath(body.html, + // match the anchor's own inline style for blue-button background-color and + // padding; avoids scanning descendant markup, which can be arbitrarily + // large per anchor and dominates cost on content-heavy messages + '//a[@href][contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"background") and (contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"0078d4") or contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"3a78d1")) and contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"padding")]' + ).nodes, // ignore links going to microsoft - and not any(.links, - ( - .href_url.domain.sld in ( - "microsoft", - "azure", - "outlook.office365", - "office365" - ) - ) - or .href_url.domain.domain in $tenant_domains - or ( - .href_url.domain.root_domain in ( - "mimecast.com", - "mimecastprotect.com" - ) - and any(.href_url.query_params_decoded['domain'], - strings.parse_domain(.).domain in ( - "microsoft.com", - "azure.com", - "outlook.office365.com", - "office365.com" - ) - or strings.parse_domain(.).domain in $tenant_domains - ) - ) + not any(.links, + ( + .href_url.domain.sld in ( + "microsoft", + "azure", + "outlook.office365", + "office365" + ) + ) + or .href_url.domain.domain in $tenant_domains + or ( + .href_url.domain.root_domain in ( + "mimecast.com", + "mimecastprotect.com" + ) + and any(.href_url.query_params_decoded['domain'], + strings.parse_domain(.).domain in ( + "microsoft.com", + "azure.com", + "outlook.office365.com", + "office365.com" + ) + or strings.parse_domain(.).domain in $tenant_domains + ) + ) ) ) and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign") From 03cbba589ab6020c398aba9d2dbb518c2eec60e8 Mon Sep 17 00:00:00 2001 From: Jonathan Katzman Date: Mon, 6 Jul 2026 10:42:16 -0400 Subject: [PATCH 2/4] Simplify redundant no-previous-threads/fake-thread condition length(body.previous_threads) == 0 OR'd with (A AND (subject.is_reply OR subject.is_forward OR length(body.previous_threads) > 0)) always reduces to just length(body.previous_threads) == 0 OR A, since the third disjunct is the exact negation of the first OR arm: P OR (A AND NOT P) == P OR A. The subject.is_reply/is_forward checks never affected the result. Verified equivalent by exhaustive truth-table test across all 32 input combinations. --- .../phishing_blue_button_file_sharing.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/detection-rules/phishing_blue_button_file_sharing.yml b/detection-rules/phishing_blue_button_file_sharing.yml index 772149d9f18..f0dc8c22968 100644 --- a/detection-rules/phishing_blue_button_file_sharing.yml +++ b/detection-rules/phishing_blue_button_file_sharing.yml @@ -5,17 +5,10 @@ severity: "low" source: | type.inbound and ( - // no previous threads + // no previous threads, or no thread references at all length(body.previous_threads) == 0 - // or is a fake thread - or ( - (length(headers.references) == 0 or headers.in_reply_to is null) - and ( - subject.is_reply - or subject.is_forward - or length(body.previous_threads) > 0 - ) - ) + or length(headers.references) == 0 + or headers.in_reply_to is null ) and any(html.xpath(body.html, // match the anchor's own inline style for blue-button background-color and From 2183043909372a80cddae94b85ead67584195e6e Mon Sep 17 00:00:00 2001 From: Jonathan Katzman Date: Mon, 6 Jul 2026 11:14:50 -0400 Subject: [PATCH 3/4] comments --- detection-rules/phishing_blue_button_file_sharing.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/detection-rules/phishing_blue_button_file_sharing.yml b/detection-rules/phishing_blue_button_file_sharing.yml index f0dc8c22968..b61f43408fc 100644 --- a/detection-rules/phishing_blue_button_file_sharing.yml +++ b/detection-rules/phishing_blue_button_file_sharing.yml @@ -11,9 +11,7 @@ source: | or headers.in_reply_to is null ) and any(html.xpath(body.html, - // match the anchor's own inline style for blue-button background-color and - // padding; avoids scanning descendant markup, which can be arbitrarily - // large per anchor and dominates cost on content-heavy messages + // blue button background or background-color and observed colors, plus padding for button styling '//a[@href][contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"background") and (contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"0078d4") or contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"3a78d1")) and contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"padding")]' ).nodes, // ignore links going to microsoft From c06be6ab02945aa69c16d08589fbc6c9768a1ff2 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Mon, 6 Jul 2026 15:18:03 +0000 Subject: [PATCH 4/4] Auto-format MQL and add rule IDs --- detection-rules/phishing_blue_button_file_sharing.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/detection-rules/phishing_blue_button_file_sharing.yml b/detection-rules/phishing_blue_button_file_sharing.yml index b61f43408fc..4e6f39b65f7 100644 --- a/detection-rules/phishing_blue_button_file_sharing.yml +++ b/detection-rules/phishing_blue_button_file_sharing.yml @@ -11,9 +11,9 @@ source: | or headers.in_reply_to is null ) and any(html.xpath(body.html, - // blue button background or background-color and observed colors, plus padding for button styling - '//a[@href][contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"background") and (contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"0078d4") or contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"3a78d1")) and contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"padding")]' - ).nodes, + // blue button background or background-color and observed colors, plus padding for button styling + '//a[@href][contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"background") and (contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"0078d4") or contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"3a78d1")) and contains(translate(@style,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"padding")]' + ).nodes, // ignore links going to microsoft not any(.links, ( @@ -52,7 +52,6 @@ source: | sender.email.domain.root_domain == "microsoft.com" and headers.auth_summary.dmarc.pass ) - attack_types: - "Credential Phishing" tactics_and_techniques: