From 9dd2f746d589792c1a1cfb341f54512087470d3e Mon Sep 17 00:00:00 2001 From: "Jacob.Mazurkiewicz2@dcsg.com" Date: Thu, 14 May 2026 14:51:15 -0400 Subject: [PATCH 01/11] Added new rule for detecting rating solicitation --- .../scam_employer_review_solicitation.yml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 detection-rules/scam_employer_review_solicitation.yml diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml new file mode 100644 index 00000000000..d924acadc6d --- /dev/null +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -0,0 +1,71 @@ +name: "Scam soliciting employer review/rating" +description: "Detects scam content that impersonates employer review/rating platforms (e.g., Glassdoor, Indeed, Comparably, Great Place to Work) and solicits the recipient to review or rate their employer, while excluding legitimate review/rating platform senders." +type: "rule" +severity: "low" +source: | + type.inbound + and ( + ( + // scam in current thread + any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("scam", "job_scam", "cred_theft") and .confidence != "low" + ) + // and employer review/rating solicitation in current thread + and regex.icontains(body.current_thread.text, + 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', + 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', + '(?:employer|company|workplace|job)\s+(?:review|rating)', + 'share\s+(?:your\s+|a\s+)?(?:review|experience|feedback|rating)', + 'leave\s+(?:a\s+|your\s+)?(?:review|rating|feedback)', + 'write\s+(?:a\s+|your\s+)?(?:review|rating)', + '(?:glassdoor|indeed|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b)' + ) + ) + // scam in previous thread + or any(body.previous_threads, + any(ml.nlu_classifier(.text).intents, + .name in ("scam", "job_scam", "cred_theft") and .confidence != "low" + ) + // and employer review/rating solicitation in previous thread + and regex.icontains(.text, + 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', + 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', + '(?:employer|company|workplace|job)\s+(?:review|rating)', + 'share\s+(?:your\s+|a\s+)?(?:review|experience|feedback|rating)', + 'leave\s+(?:a\s+|your\s+)?(?:review|rating|feedback)', + 'write\s+(?:a\s+|your\s+)?(?:review|rating)', + '(?:glassdoor|indeed|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b)' + ) + ) + ) + and length(body.current_thread.links) < 10 + + // negating legitimate employer review/rating senders + and not ( + sender.email.domain.root_domain in ( + 'glassdoor.com', + 'indeed.com', + 'comparably.com', + 'greatplacetowork.com', + 'builtin.com', + 'linkedin.com', + 'lensa.com', + 'ziprecruiter.com', + 'kununu.com', + 'jobcase.com', + 'trustpilot.com' + ) + and headers.auth_summary.dmarc.pass + ) +attack_types: + - "BEC/Fraud" + - "Credential Phishing" +tactics_and_techniques: + - "Social engineering" + - "Impersonation: Brand" +detection_methods: + - "Content analysis" + - "Natural Language Understanding" + - "Header analysis" + - "Sender analysis" +id: "ad3c63e8-02a8-5583-bb60-e5ebd76d0331" From 3153ddb4cfdd62beaba80eaea90e4169f34eda6e Mon Sep 17 00:00:00 2001 From: CI Bot Date: Fri, 15 May 2026 11:45:08 +0000 Subject: [PATCH 02/11] Auto-format MQL and add rule IDs --- detection-rules/scam_employer_review_solicitation.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index d924acadc6d..33cf1c09ed6 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -24,7 +24,8 @@ source: | // scam in previous thread or any(body.previous_threads, any(ml.nlu_classifier(.text).intents, - .name in ("scam", "job_scam", "cred_theft") and .confidence != "low" + .name in ("scam", "job_scam", "cred_theft") + and .confidence != "low" ) // and employer review/rating solicitation in previous thread and regex.icontains(.text, @@ -39,7 +40,7 @@ source: | ) ) and length(body.current_thread.links) < 10 - + // negating legitimate employer review/rating senders and not ( sender.email.domain.root_domain in ( From 5ef2c2acfdc890efff426317c846d32a05a48fa8 Mon Sep 17 00:00:00 2001 From: jacob-mazurkiewicz Date: Fri, 22 May 2026 11:59:07 -0400 Subject: [PATCH 03/11] Update detection-rules/scam_employer_review_solicitation.yml Co-authored-by: Luke Wescott <69780712+IndiaAce@users.noreply.github.com> --- detection-rules/scam_employer_review_solicitation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 33cf1c09ed6..91fb6a51116 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -8,7 +8,7 @@ source: | ( // scam in current thread any(ml.nlu_classifier(body.current_thread.text).intents, - .name in ("scam", "job_scam", "cred_theft") and .confidence != "low" + .name in ("job_scam", "cred_theft") and .confidence != "low" ) // and employer review/rating solicitation in current thread and regex.icontains(body.current_thread.text, From 833573511a1065a037fb47181a4abf04e1de2040 Mon Sep 17 00:00:00 2001 From: jacob-mazurkiewicz Date: Fri, 22 May 2026 12:00:03 -0400 Subject: [PATCH 04/11] Update detection-rules/scam_employer_review_solicitation.yml Co-authored-by: Luke Wescott <69780712+IndiaAce@users.noreply.github.com> --- .../scam_employer_review_solicitation.yml | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 91fb6a51116..5526bce8ace 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -43,20 +43,20 @@ source: | // negating legitimate employer review/rating senders and not ( - sender.email.domain.root_domain in ( - 'glassdoor.com', - 'indeed.com', - 'comparably.com', - 'greatplacetowork.com', - 'builtin.com', - 'linkedin.com', - 'lensa.com', - 'ziprecruiter.com', - 'kununu.com', - 'jobcase.com', - 'trustpilot.com' + ( + sender.email.domain.root_domain in ( + 'comparably.com', + 'greatplacetowork.com', + 'builtin.com', + 'lensa.com', + 'ziprecruiter.com', + 'kununu.com', + 'jobcase.com', + 'trustpilot.com' + ) + or sender.email.domain.root_domain in $high_trust_sender_root_domains ) - and headers.auth_summary.dmarc.pass + and coalesce(headers.auth_summary.dmarc.pass, false) ) attack_types: - "BEC/Fraud" From 389a8fe7b826b30982e25fc59395f816d894f32e Mon Sep 17 00:00:00 2001 From: jacob-mazurkiewicz Date: Fri, 22 May 2026 12:00:12 -0400 Subject: [PATCH 05/11] Update detection-rules/scam_employer_review_solicitation.yml Co-authored-by: Luke Wescott <69780712+IndiaAce@users.noreply.github.com> --- detection-rules/scam_employer_review_solicitation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 5526bce8ace..69ca8b6c6b0 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -24,7 +24,7 @@ source: | // scam in previous thread or any(body.previous_threads, any(ml.nlu_classifier(.text).intents, - .name in ("scam", "job_scam", "cred_theft") + .name in ("job_scam", "cred_theft") and .confidence != "low" ) // and employer review/rating solicitation in previous thread From 5e022e4c761ce7072b3d57dd9f1cd76a3f6b26e8 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Fri, 22 May 2026 16:01:22 +0000 Subject: [PATCH 06/11] Auto-format MQL and add rule IDs --- detection-rules/scam_employer_review_solicitation.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 69ca8b6c6b0..c4b7bc43c0a 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -24,8 +24,7 @@ source: | // scam in previous thread or any(body.previous_threads, any(ml.nlu_classifier(.text).intents, - .name in ("job_scam", "cred_theft") - and .confidence != "low" + .name in ("job_scam", "cred_theft") and .confidence != "low" ) // and employer review/rating solicitation in previous thread and regex.icontains(.text, From 2b58b3c0b7d10cb5dc5276e3f97ef6b200f5195f Mon Sep 17 00:00:00 2001 From: "Jacob.Mazurkiewicz2@dcsg.com" Date: Fri, 22 May 2026 12:18:16 -0400 Subject: [PATCH 07/11] Hardened defense against FPs, added checks for instruction sets, expanded topic set for nlu_classifier flags --- .../scam_employer_review_solicitation.yml | 136 ++++++++++++++++-- 1 file changed, 126 insertions(+), 10 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index c4b7bc43c0a..c11b4a16ee9 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -12,13 +12,64 @@ source: | ) // and employer review/rating solicitation in current thread and regex.icontains(body.current_thread.text, + // explicit employer-context patterns 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', '(?:employer|company|workplace|job)\s+(?:review|rating)', - 'share\s+(?:your\s+|a\s+)?(?:review|experience|feedback|rating)', - 'leave\s+(?:a\s+|your\s+)?(?:review|rating|feedback)', - 'write\s+(?:a\s+|your\s+)?(?:review|rating)', - '(?:glassdoor|indeed|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b)' + // generic share/leave/write — require employer context within 80 chars to avoid doc/proposal FPs + '(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)[^\r\n]{0,80}(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)', + '(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)[^\r\n]{0,80}(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)', + // explicit brand mention + '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b|lensa|ziprecruiter|kununu|jobcase|trustpilot)' + ) + // tuned through sandbox sample testing + and any(ml.nlu_classifier(body.current_thread.text).topics, + .name in ("Advertising and Promotions", "Professional and Career Development", "Reminders and Notifications", "Financial Communications") + and .confidence != "low" + ) + // instructions/steps provided to the user (numbered, stepped, or bulleted list) + and ( + // numbered list — both "1." and "2." present at line start + ( + regex.icontains(body.current_thread.text, '(?:^|\n)\s*1[\.\)]\s+\S') + and regex.icontains(body.current_thread.text, '(?:^|\n)\s*2[\.\)]\s+\S') + ) + // explicit "Step 1" + "Step 2" instructions + or ( + regex.icontains(body.current_thread.text, 'step\s*[#:\-]?\s*1\b') + and regex.icontains(body.current_thread.text, 'step\s*[#:\-]?\s*2\b') + ) + // explicit "follow these steps" / "how it works" / "instructions below" + or regex.icontains(body.current_thread.text, + 'follow\s+(?:these|the\s+below|the\s+following)\s+(?:simple\s+|quick\s+|easy\s+)?(?:steps|instructions)', + 'how\s+(?:to|it)\s+works\s*:', + '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', + 'instructions\s+(?:below|to\s+follow)', + 'here(?:\s+is\s+how|\'?s\s+how|\s+are\s+the\s+steps)' + ) + // two or more bullet items (•, *) at line start + or length(regex.extract(body.current_thread.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 + ) + // incentive/reward language identifiers + and regex.icontains(body.current_thread.text, + 'gift\s*card', + '\$\d{1,4}(?:\.\d{2})?\s*(?:amazon|visa|target|walmart|gift|reward|bonus|incentive|voucher)', + '(?:amazon|visa|target|walmart|starbucks)\s*(?:gift\s*card|voucher|e?[- ]?card)', + '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', + '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', + 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', + 'we\'?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', + 'you\'?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', + 'paid\s+(?:review|feedback|opportunity|survey)', + 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' + ) + // not document/proposal/file sharing context (outside scope of this rule) + and not regex.icontains(body.current_thread.text, + 'review\s+(?:the\s+|this\s+|my\s+|our\s+|attached\s+|enclosed\s+)?(?:attached\s+)?(?:document|proposal|file|attachment|deck|presentation|contract|pdf|draft|report|spreadsheet|agreement|nda|sow|quote|estimate|invoice|design|mockup|wireframe)', + '(?:document|proposal|file|attachment|deck|presentation|contract|draft|spreadsheet|report)\s+(?:is\s+ready\s+)?(?:for|awaiting)\s+(?:your\s+)?(?:review|feedback)', + 'shared\s+(?:a|the|this)\s+(?:document|file|folder|proposal|deck|presentation|spreadsheet)\s+with\s+you', + 'please\s+(?:see|find|review)\s+(?:the\s+)?attached', + 'feedback\s+on\s+(?:the|this|my|our|attached)\s+(?:attached\s+)?(?:document|proposal|file|deck|draft|presentation|contract|report|spreadsheet|design|mockup)' ) ) // scam in previous thread @@ -31,16 +82,81 @@ source: | 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', '(?:employer|company|workplace|job)\s+(?:review|rating)', - 'share\s+(?:your\s+|a\s+)?(?:review|experience|feedback|rating)', - 'leave\s+(?:a\s+|your\s+)?(?:review|rating|feedback)', - 'write\s+(?:a\s+|your\s+)?(?:review|rating)', - '(?:glassdoor|indeed|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b)' + '(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)[^\r\n]{0,80}(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)', + '(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)[^\r\n]{0,80}(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)', + '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b|lensa|ziprecruiter|kununu|jobcase|trustpilot)' + ) + // tuned through sandbox sample testing + and any(ml.nlu_classifier(.text).topics, + .name in ("Advertising and Promotions", "Professional and Career Development", "Reminders and Notifications", "Financial Communications") + and .confidence != "low" + ) + // instructions/steps provided to the user (numbered, stepped, or bulleted list) + and ( + // numbered list — both "1." and "2." present at line start + ( + regex.icontains(.text, '(?:^|\n)\s*1[\.\)]\s+\S') + and regex.icontains(.text, '(?:^|\n)\s*2[\.\)]\s+\S') + ) + // explicit "Step 1" + "Step 2" instructions + or ( + regex.icontains(.text, 'step\s*[#:\-]?\s*1\b') + and regex.icontains(.text, 'step\s*[#:\-]?\s*2\b') + ) + // explicit "follow these steps" / "how it works" / "instructions below" + or regex.icontains(.text, + 'follow\s+(?:these|the\s+below|the\s+following)\s+(?:simple\s+|quick\s+|easy\s+)?(?:steps|instructions)', + 'how\s+(?:to|it)\s+works\s*:', + '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', + 'instructions\s+(?:below|to\s+follow)', + 'here(?:\s+is\s+how|\'?s\s+how|\s+are\s+the\s+steps)' + ) + // two or more bullet items (•, *) at line start + or length(regex.extract(.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 + ) + // incentive/reward language identifiers + and regex.icontains(.text, + 'gift\s*card', + '\$\d{1,4}(?:\.\d{2})?\s*(?:amazon|visa|target|walmart|gift|reward|bonus|incentive|voucher)', + '(?:amazon|visa|target|walmart|starbucks)\s*(?:gift\s*card|voucher|e?[- ]?card)', + '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', + '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', + 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', + 'we\'?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', + 'you\'?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', + 'paid\s+(?:review|feedback|opportunity|survey)', + 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' + ) + // not document/proposal/file sharing context (outside scope of this rule) + and not regex.icontains(.text, + 'review\s+(?:the\s+|this\s+|my\s+|our\s+|attached\s+|enclosed\s+)?(?:attached\s+)?(?:document|proposal|file|attachment|deck|presentation|contract|pdf|draft|report|spreadsheet|agreement|nda|sow|quote|estimate|invoice|design|mockup|wireframe)', + '(?:document|proposal|file|attachment|deck|presentation|contract|draft|spreadsheet|report)\s+(?:is\s+ready\s+)?(?:for|awaiting)\s+(?:your\s+)?(?:review|feedback)', + 'shared\s+(?:a|the|this)\s+(?:document|file|folder|proposal|deck|presentation|spreadsheet)\s+with\s+you', + 'please\s+(?:see|find|review)\s+(?:the\s+)?attached', + 'feedback\s+on\s+(?:the|this|my|our|attached)\s+(?:attached\s+)?(?:document|proposal|file|deck|draft|presentation|contract|report|spreadsheet|design|mockup)' ) ) ) and length(body.current_thread.links) < 10 - - // negating legitimate employer review/rating senders + + // subject cites employer review / rating / feedback context + and regex.icontains(subject.subject, + 'review', + 'rating', + '\brate\b', + 'feedback', + 'testimonial', + '(?:employer|workplace|company|employee|job)', + '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|built\s?in|lensa|ziprecruiter|kununu|jobcase|trustpilot)', + 'experience', + 'survey', + 'opinion' + ) + + // unsolicited sender + and not profile.by_sender().solicited + + // negating legitimate/trusted employer review/rating senders and not ( ( sender.email.domain.root_domain in ( From 32616b708cc288e58d172a414a9fa1f9a5560187 Mon Sep 17 00:00:00 2001 From: "Jacob.Mazurkiewicz2@dcsg.com" Date: Fri, 22 May 2026 12:22:04 -0400 Subject: [PATCH 08/11] Fixed apostrophe escaping errors --- .../scam_employer_review_solicitation.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index c11b4a16ee9..6b918d20709 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -45,7 +45,7 @@ source: | 'how\s+(?:to|it)\s+works\s*:', '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', 'instructions\s+(?:below|to\s+follow)', - 'here(?:\s+is\s+how|\'?s\s+how|\s+are\s+the\s+steps)' + 'here(?:\s+is\s+how|''?s\s+how|\s+are\s+the\s+steps)' ) // two or more bullet items (•, *) at line start or length(regex.extract(body.current_thread.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 @@ -58,8 +58,8 @@ source: | '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', - 'we\'?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', - 'you\'?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', + 'we''?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', + 'you''?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', 'paid\s+(?:review|feedback|opportunity|survey)', 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' ) @@ -109,7 +109,7 @@ source: | 'how\s+(?:to|it)\s+works\s*:', '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', 'instructions\s+(?:below|to\s+follow)', - 'here(?:\s+is\s+how|\'?s\s+how|\s+are\s+the\s+steps)' + 'here(?:\s+is\s+how|''?s\s+how|\s+are\s+the\s+steps)' ) // two or more bullet items (•, *) at line start or length(regex.extract(.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 @@ -122,8 +122,8 @@ source: | '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', - 'we\'?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', - 'you\'?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', + 'we''?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', + 'you''?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', 'paid\s+(?:review|feedback|opportunity|survey)', 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' ) From c022b5142678fc40bc840212a7788fe8c6b8f288 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Fri, 22 May 2026 16:23:15 +0000 Subject: [PATCH 09/11] Auto-format MQL and add rule IDs --- .../scam_employer_review_solicitation.yml | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 6b918d20709..24dc15de57a 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -23,8 +23,13 @@ source: | '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b|lensa|ziprecruiter|kununu|jobcase|trustpilot)' ) // tuned through sandbox sample testing - and any(ml.nlu_classifier(body.current_thread.text).topics, - .name in ("Advertising and Promotions", "Professional and Career Development", "Reminders and Notifications", "Financial Communications") + and any(ml.nlu_classifier(body.current_thread.text).topics, + .name in ( + "Advertising and Promotions", + "Professional and Career Development", + "Reminders and Notifications", + "Financial Communications" + ) and .confidence != "low" ) // instructions/steps provided to the user (numbered, stepped, or bulleted list) @@ -48,7 +53,8 @@ source: | 'here(?:\s+is\s+how|''?s\s+how|\s+are\s+the\s+steps)' ) // two or more bullet items (•, *) at line start - or length(regex.extract(body.current_thread.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 + or length(regex.extract(body.current_thread.text, '(?:^|\n)\s*[•\*]\s+\S') + ) >= 2 ) // incentive/reward language identifiers and regex.icontains(body.current_thread.text, @@ -88,7 +94,12 @@ source: | ) // tuned through sandbox sample testing and any(ml.nlu_classifier(.text).topics, - .name in ("Advertising and Promotions", "Professional and Career Development", "Reminders and Notifications", "Financial Communications") + .name in ( + "Advertising and Promotions", + "Professional and Career Development", + "Reminders and Notifications", + "Financial Communications" + ) and .confidence != "low" ) // instructions/steps provided to the user (numbered, stepped, or bulleted list) @@ -138,7 +149,7 @@ source: | ) ) and length(body.current_thread.links) < 10 - + // subject cites employer review / rating / feedback context and regex.icontains(subject.subject, 'review', @@ -152,10 +163,10 @@ source: | 'survey', 'opinion' ) - + // unsolicited sender and not profile.by_sender().solicited - + // negating legitimate/trusted employer review/rating senders and not ( ( From 53dbb1ae0346347ab6f1f8848caacac16b66d7e9 Mon Sep 17 00:00:00 2001 From: "Jacob.Mazurkiewicz2@dcsg.com" Date: Mon, 1 Jun 2026 06:42:41 -0400 Subject: [PATCH 10/11] Scoped rule further to hierarchical malicious intent -> job review scam level detection --- .../scam_employer_review_solicitation.yml | 227 ++++-------------- 1 file changed, 52 insertions(+), 175 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 24dc15de57a..969bb8330da 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -3,187 +3,64 @@ description: "Detects scam content that impersonates employer review/rating plat type: "rule" severity: "low" source: | - type.inbound - and ( - ( - // scam in current thread - any(ml.nlu_classifier(body.current_thread.text).intents, - .name in ("job_scam", "cred_theft") and .confidence != "low" - ) - // and employer review/rating solicitation in current thread - and regex.icontains(body.current_thread.text, - // explicit employer-context patterns - 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', - 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', - '(?:employer|company|workplace|job)\s+(?:review|rating)', - // generic share/leave/write — require employer context within 80 chars to avoid doc/proposal FPs - '(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)[^\r\n]{0,80}(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)', - '(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)[^\r\n]{0,80}(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)', - // explicit brand mention - '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b|lensa|ziprecruiter|kununu|jobcase|trustpilot)' + type.inbound + // credential theft or scam intent + and any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("cred_theft", "job_scam") and .confidence != "low" + ) + // employer/workplace review solicitation phrasing + and regex.icontains(body.current_thread.text, + '\brate\s+(?:your\s+)?(?:employer|workplace|job)\b', + '\breview\s+(?:your\s+)?(?:experience\s+(?:at|with)\s+(?:your|the)\s)', + '\b(?:employer|workplace|job)\s+(?:review|rating|feedback)\b', + '\bleave\s+(?:a\s+)?(?:review|rating).{0,40}(?:employer|workplace|job)', + '(?:glassdoor|comparably|great\s+place\s+to\s+work|kununu|jobcase).{0,40}(?:review|rate|rating|feedback)' + ) + and ( + // credential harvesting + regex.icontains(body.current_thread.text, + '(?:enter|provide|confirm|verify).{0,40}(?:password|credentials|login|email\s+and\s+password)', + 'verify\s+your\s+(?:identity|eligibility|account|profile)', + '(?:password|credential|login).{0,30}(?:enter|provide|confirm|verify|required)' ) - // tuned through sandbox sample testing - and any(ml.nlu_classifier(body.current_thread.text).topics, - .name in ( - "Advertising and Promotions", - "Professional and Career Development", - "Reminders and Notifications", - "Financial Communications" - ) - and .confidence != "low" + // or monetary incentive + or regex.icontains(body.current_thread.text, + 'gift.?card', + '(?:receive|earn|get|claim).{0,30}[\$€£]\d+', + '[\$€£]\d+.{0,30}(?:gift|reward|credit|incentive|voucher|bonus|prize)', + 'token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude)' ) - // instructions/steps provided to the user (numbered, stepped, or bulleted list) - and ( - // numbered list — both "1." and "2." present at line start - ( - regex.icontains(body.current_thread.text, '(?:^|\n)\s*1[\.\)]\s+\S') - and regex.icontains(body.current_thread.text, '(?:^|\n)\s*2[\.\)]\s+\S') - ) - // explicit "Step 1" + "Step 2" instructions - or ( - regex.icontains(body.current_thread.text, 'step\s*[#:\-]?\s*1\b') - and regex.icontains(body.current_thread.text, 'step\s*[#:\-]?\s*2\b') - ) - // explicit "follow these steps" / "how it works" / "instructions below" - or regex.icontains(body.current_thread.text, - 'follow\s+(?:these|the\s+below|the\s+following)\s+(?:simple\s+|quick\s+|easy\s+)?(?:steps|instructions)', - 'how\s+(?:to|it)\s+works\s*:', - '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', - 'instructions\s+(?:below|to\s+follow)', - 'here(?:\s+is\s+how|''?s\s+how|\s+are\s+the\s+steps)' + ) + // negating legitimate/trusted employer review/rating senders + and not ( + ( + sender.email.domain.root_domain in ( + 'comparably.com', + 'greatplacetowork.com', + 'builtin.com', + 'lensa.com', + 'ziprecruiter.com', + 'kununu.com', + 'jobcase.com', + 'trustpilot.com' ) - // two or more bullet items (•, *) at line start - or length(regex.extract(body.current_thread.text, '(?:^|\n)\s*[•\*]\s+\S') - ) >= 2 - ) - // incentive/reward language identifiers - and regex.icontains(body.current_thread.text, - 'gift\s*card', - '\$\d{1,4}(?:\.\d{2})?\s*(?:amazon|visa|target|walmart|gift|reward|bonus|incentive|voucher)', - '(?:amazon|visa|target|walmart|starbucks)\s*(?:gift\s*card|voucher|e?[- ]?card)', - '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', - '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', - 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', - 'we''?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', - 'you''?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', - 'paid\s+(?:review|feedback|opportunity|survey)', - 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' - ) - // not document/proposal/file sharing context (outside scope of this rule) - and not regex.icontains(body.current_thread.text, - 'review\s+(?:the\s+|this\s+|my\s+|our\s+|attached\s+|enclosed\s+)?(?:attached\s+)?(?:document|proposal|file|attachment|deck|presentation|contract|pdf|draft|report|spreadsheet|agreement|nda|sow|quote|estimate|invoice|design|mockup|wireframe)', - '(?:document|proposal|file|attachment|deck|presentation|contract|draft|spreadsheet|report)\s+(?:is\s+ready\s+)?(?:for|awaiting)\s+(?:your\s+)?(?:review|feedback)', - 'shared\s+(?:a|the|this)\s+(?:document|file|folder|proposal|deck|presentation|spreadsheet)\s+with\s+you', - 'please\s+(?:see|find|review)\s+(?:the\s+)?attached', - 'feedback\s+on\s+(?:the|this|my|our|attached)\s+(?:attached\s+)?(?:document|proposal|file|deck|draft|presentation|contract|report|spreadsheet|design|mockup)' + or sender.email.domain.root_domain in $high_trust_sender_root_domains ) + and coalesce(headers.auth_summary.dmarc.pass, false) ) - // scam in previous thread - or any(body.previous_threads, - any(ml.nlu_classifier(.text).intents, - .name in ("job_scam", "cred_theft") and .confidence != "low" - ) - // and employer review/rating solicitation in previous thread - and regex.icontains(.text, - 'review\s+(?:your\s+)?(?:experience|employer|workplace|company|job)', - 'rate\s+(?:your\s+)?(?:employer|workplace|company|experience|job)', - '(?:employer|company|workplace|job)\s+(?:review|rating)', - '(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)[^\r\n]{0,80}(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)', - '(?:employer|workplace|company|job|us|our\s+(?:team|company|workplace|business|employer)|the\s+company)[^\r\n]{0,80}(?:share|leave|write|submit|post|drop)\s+(?:a\s+|an\s+|your\s+)?(?:honest\s+|positive\s+|quick\s+|brief\s+|5[- ]?star\s+|great\s+)?(?:review|rating|feedback|testimonial)', - '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|\bbuilt\s?in\b|lensa|ziprecruiter|kununu|jobcase|trustpilot)' - ) - // tuned through sandbox sample testing - and any(ml.nlu_classifier(.text).topics, - .name in ( - "Advertising and Promotions", - "Professional and Career Development", - "Reminders and Notifications", - "Financial Communications" - ) - and .confidence != "low" - ) - // instructions/steps provided to the user (numbered, stepped, or bulleted list) - and ( - // numbered list — both "1." and "2." present at line start - ( - regex.icontains(.text, '(?:^|\n)\s*1[\.\)]\s+\S') - and regex.icontains(.text, '(?:^|\n)\s*2[\.\)]\s+\S') - ) - // explicit "Step 1" + "Step 2" instructions - or ( - regex.icontains(.text, 'step\s*[#:\-]?\s*1\b') - and regex.icontains(.text, 'step\s*[#:\-]?\s*2\b') - ) - // explicit "follow these steps" / "how it works" / "instructions below" - or regex.icontains(.text, - 'follow\s+(?:these|the\s+below|the\s+following)\s+(?:simple\s+|quick\s+|easy\s+)?(?:steps|instructions)', - 'how\s+(?:to|it)\s+works\s*:', - '(?:simple\s+|quick\s+|easy\s+|these\s+)?steps\s+(?:to|below)\s+(?:leave|share|write|complete|submit|post)', - 'instructions\s+(?:below|to\s+follow)', - 'here(?:\s+is\s+how|''?s\s+how|\s+are\s+the\s+steps)' - ) - // two or more bullet items (•, *) at line start - or length(regex.extract(.text, '(?:^|\n)\s*[•\*]\s+\S')) >= 2 - ) - // incentive/reward language identifiers - and regex.icontains(.text, - 'gift\s*card', - '\$\d{1,4}(?:\.\d{2})?\s*(?:amazon|visa|target|walmart|gift|reward|bonus|incentive|voucher)', - '(?:amazon|visa|target|walmart|starbucks)\s*(?:gift\s*card|voucher|e?[- ]?card)', - '(?:as\s+a|small)\s+(?:thank[- ]you|token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude))', - '(?:reward|incentive|compensation|bonus|prize|payment)\s+(?:for|of)\s+(?:your\s+)?(?:time|participation|review|feedback|completion)', - 'in\s+(?:exchange|return)\s+for\s+(?:your\s+)?(?:review|feedback|rating|time|participation)', - 'we''?ll?\s+(?:send|give|reward|compensate|gift|mail)\s+you\b', - 'you''?ll?\s+(?:receive|get|earn)\s+(?:a\s+|an\s+|\$)', - 'paid\s+(?:review|feedback|opportunity|survey)', - 'compensated\s+(?:for|with)\s+(?:your\s+)?(?:time|review|feedback|participation)' - ) - // not document/proposal/file sharing context (outside scope of this rule) - and not regex.icontains(.text, - 'review\s+(?:the\s+|this\s+|my\s+|our\s+|attached\s+|enclosed\s+)?(?:attached\s+)?(?:document|proposal|file|attachment|deck|presentation|contract|pdf|draft|report|spreadsheet|agreement|nda|sow|quote|estimate|invoice|design|mockup|wireframe)', - '(?:document|proposal|file|attachment|deck|presentation|contract|draft|spreadsheet|report)\s+(?:is\s+ready\s+)?(?:for|awaiting)\s+(?:your\s+)?(?:review|feedback)', - 'shared\s+(?:a|the|this)\s+(?:document|file|folder|proposal|deck|presentation|spreadsheet)\s+with\s+you', - 'please\s+(?:see|find|review)\s+(?:the\s+)?attached', - 'feedback\s+on\s+(?:the|this|my|our|attached)\s+(?:attached\s+)?(?:document|proposal|file|deck|draft|presentation|contract|report|spreadsheet|design|mockup)' - ) - ) - ) - and length(body.current_thread.links) < 10 - - // subject cites employer review / rating / feedback context - and regex.icontains(subject.subject, - 'review', - 'rating', - '\brate\b', - 'feedback', - 'testimonial', - '(?:employer|workplace|company|employee|job)', - '(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|built\s?in|lensa|ziprecruiter|kununu|jobcase|trustpilot)', - 'experience', - 'survey', - 'opinion' - ) - - // unsolicited sender - and not profile.by_sender().solicited - - // negating legitimate/trusted employer review/rating senders - and not ( - ( - sender.email.domain.root_domain in ( - 'comparably.com', - 'greatplacetowork.com', - 'builtin.com', - 'lensa.com', - 'ziprecruiter.com', - 'kununu.com', - 'jobcase.com', - 'trustpilot.com' - ) - or sender.email.domain.root_domain in $high_trust_sender_root_domains + // subject cites employer review / rating / feedback context + and regex.icontains(subject.subject, + '\breview\b', + '\brating\b', + '\brate\b', + '\bfeedback\b', + '\btestimonial\b', + '\b(?:employer|workplace|company|employee|job)\b', + '\b(?:glassdoor|indeed|linkedin|comparably|great\s+place\s+to\s+work|built\s?in|lensa|ziprecruiter|kununu|jobcase|trustpilot)\b', + '\bexperience\b', + '\bsurvey\b', + '\bopinion\b' ) - and coalesce(headers.auth_summary.dmarc.pass, false) - ) attack_types: - "BEC/Fraud" - "Credential Phishing" From 42cbb91ecda9bc019c27364d02e81ccf4715ff76 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Mon, 1 Jun 2026 10:44:00 +0000 Subject: [PATCH 11/11] Auto-format MQL and add rule IDs --- detection-rules/scam_employer_review_solicitation.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/detection-rules/scam_employer_review_solicitation.yml b/detection-rules/scam_employer_review_solicitation.yml index 969bb8330da..e8eea1c645b 100644 --- a/detection-rules/scam_employer_review_solicitation.yml +++ b/detection-rules/scam_employer_review_solicitation.yml @@ -25,10 +25,10 @@ source: | ) // or monetary incentive or regex.icontains(body.current_thread.text, - 'gift.?card', - '(?:receive|earn|get|claim).{0,30}[\$€£]\d+', - '[\$€£]\d+.{0,30}(?:gift|reward|credit|incentive|voucher|bonus|prize)', - 'token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude)' + 'gift.?card', + '(?:receive|earn|get|claim).{0,30}[\$€£]\d+', + '[\$€£]\d+.{0,30}(?:gift|reward|credit|incentive|voucher|bonus|prize)', + 'token\s+of\s+(?:our\s+)?(?:appreciation|thanks|gratitude)' ) ) // negating legitimate/trusted employer review/rating senders