Detection rules › Sublime MQL
Sublime MQL rules: body
Advance Fee Fraud (AFF) from freemail provider or suspicious TLD
#Advance Fee Fraud (AFF) is a type of BEC/Fraud involving upfront fees for promised future returns, such as lottery scams, inheritance payouts, and investment opportunities. This rule identifies messages from Freemail domains or suspicious TLDS, including those with suspicious reply-to addresses. It utilizes Natural Language Understanding to detect AFF language in their contents.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
sender.email.domain.domain in $free_email_providers
or (
length(headers.reply_to) > 0
and all(headers.reply_to,
(
.email.domain.root_domain in $free_email_providers
or .email.domain.tld in $suspicious_tlds
or (
network.whois(.email.domain).days_old < 365
and length(coalesce(body.html.raw, "")) == 0
)
)
and .email.email != sender.email.email
)
)
or sender.email.domain.tld in $suspicious_tlds
or any(["jp", "jo"], strings.iends_with(sender.email.domain.tld, .))
or (
length(recipients.to) == 0
and any(headers.reply_to,
.email.domain.root_domain != sender.email.domain.root_domain
)
)
)
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "advance_fee" and .confidence in ("medium", "high")
)
or (
length(body.current_thread.text) < 200
and regex.icontains(body.current_thread.text,
'(?:donation|inheritence|\$\d,\d{3}\,\d{3}|lottery)'
)
and not regex.icontains(body.current_thread.text,
'(?:closed.{0,50})?\$\d,\d{3}\,\d{3}.{0,100}(?:homes|realty|sale)?'
)
and not any(body.links,
regex.icontains(.href_url.url,
'(?:donation|inheritence|\$\d,\d{3}\,\d{3}|lottery)'
)
)
and (
(
(length(headers.references) > 0 or headers.in_reply_to is null)
and not (
(
strings.istarts_with(subject.subject, "RE:")
// out of office auto-reply
or strings.istarts_with(subject.subject, "Automatic reply:")
or strings.istarts_with(subject.subject, "R:")
or strings.istarts_with(subject.subject, "ODG:")
or strings.istarts_with(subject.subject, "答复:")
or strings.istarts_with(subject.subject, "AW:")
or strings.istarts_with(subject.subject, "TR:")
or strings.istarts_with(subject.subject, "FWD:")
or regex.icontains(subject.subject,
'^(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:'
)
)
)
)
or any(headers.reply_to, .email.email != sender.email.email)
)
)
)
and (
not profile.by_sender().solicited
or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign
Detection Logic
Scope: inbound message.
Advance Fee Fraud (AFF) is a type of BEC/Fraud involving upfront fees for promised future returns, such as lottery scams, inheritance payouts, and investment opportunities. This rule identifies messages from Freemail domains or suspicious TLDS, including those with suspicious reply-to addresses. It utilizes Natural Language Understanding to detect AFF language in their contents.
- inbound message
any of:
- sender.email.domain.domain in $free_email_providers
all of:
- length(headers.reply_to) > 0
all of
headers.reply_towhere all hold:any of:
- .email.domain.root_domain in $free_email_providers
- .email.domain.tld in $suspicious_tlds
all of:
- network.whois(.email.domain).days_old < 365
- length(coalesce(body.html.raw, "")) == 0
- .email.email is not sender.email.email
- sender.email.domain.tld in $suspicious_tlds
- any(["jp", "jo"], strings.iends_with(sender.email.domain.tld, .))
all of:
- length(recipients.to) == 0
any of
headers.reply_towhere:- .email.domain.root_domain is not sender.email.domain.root_domain
any of:
- any(ml.nlu_classifier(body.current_thread.text).intents, .name == "advance_fee" and .confidence in ("medium", "high") )
all of:
- length(body.current_thread.text) < 200
- body.current_thread.text matches '(?:donation|inheritence|\\$\\d,\\d{3}\\,\\d{3}|lottery)'
not:
- body.current_thread.text matches '(?:closed.{0,50})?\\$\\d,\\d{3}\\,\\d{3}.{0,100}(?:homes|realty|sale)?'
not:
any of
body.linkswhere:- .href_url.url matches '(?:donation|inheritence|\\$\\d,\\d{3}\\,\\d{3}|lottery)'
any of:
all of:
any of:
- length(headers.references) > 0
- headers.in_reply_to is missing
none of:
- subject.subject starts with 'RE:'
- subject.subject starts with 'Automatic reply:'
- subject.subject starts with 'R:'
- subject.subject starts with 'ODG:'
- subject.subject starts with '答复:'
- subject.subject starts with 'AW:'
- subject.subject starts with 'TR:'
- subject.subject starts with 'FWD:'
- subject.subject matches '^(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?)\\s?:'
any of
headers.reply_towhere:- .email.email is not sender.email.email
any of:
not:
- profile.by_sender().solicited
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
Inspects: body.current_thread.text, body.html.raw, body.links, body.links[].href_url.url, headers.in_reply_to, headers.references, headers.reply_to, headers.reply_to[].email.domain, headers.reply_to[].email.domain.root_domain, headers.reply_to[].email.domain.tld, headers.reply_to[].email.email, recipients.to, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.domain.tld, sender.email.email, subject.subject, type.inbound. Sensors: ml.nlu_classifier, network.whois, profile.by_sender, regex.icontains, strings.iends_with, strings.istarts_with. Reference lists: $free_email_providers, $suspicious_tlds.
Indicators Matched (4)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | advance_fee |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | medium |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | high |
regex.icontains | regex | (?:donation|inheritence|\$\d,\d{3}\,\d{3}|lottery) |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
and
not
or
subject.subject regex_match "^(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?)\\s?:"
subject.subject starts_with "AW:"
subject.subject starts_with "Automatic reply:"
subject.subject starts_with "FWD:"
subject.subject starts_with "ODG:"
subject.subject starts_with "R:"
subject.subject starts_with "RE:"
subject.subject starts_with "TR:"
subject.subject starts_with "答复:"
or
headers.in_reply_to is_null
headers.references length_compare "0"
any(headers.reply_to)
headers.reply_to.email.email cross_field_compare "sender.email.email"
not
any(body.links)
body.links.href_url.url regex_match "(?:donation|inheritence|\\$\\d,\\d{3}\\,\\d{3}|lottery)"
not
body.current_thread.text regex_match "(?:closed.{0,50})?\\$\\d,\\d{3}\\,\\d{3}.{0,100}(?:homes|realty|sale)?"
body.current_thread.text length_compare "200"
body.current_thread.text regex_match "(?:donation|inheritence|\\$\\d,\\d{3}\\,\\d{3}|lottery)"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name == \"advance_fee\" and .confidence in (\"medium\", \"high\")\n )"
or
and
any(headers.reply_to)
headers.reply_to.email.domain.root_domain cross_field_compare "sender.email.domain.root_domain"
recipients.to length_compare "0"
and
headers.reply_to length_compare "0"
macro "all(headers.reply_to,\n (\n .email.domain.root_domain in $free_email_providers\n or .email.domain.tld in $suspicious_tlds\n or (\n network.whois(.email.domain).days_old < 365\n and length(coalesce(body.html.raw, \"\")) == 0\n )\n )\n and .email.email != sender.email.email\n )"
sender.email.domain.domain macro "sender.email.domain.domain in free_email_providers"
sender.email.domain.tld macro "sender.email.domain.tld in suspicious_tlds"
macro "any([\"jp\", \"jo\"], strings.iends_with(sender.email.domain.tld, .))"
or
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"(?:donation|inheritence|$\d,\d{3}\,\d{3}|lottery)" |
headers.in_reply_to | is_null | field:"headers.in_reply_to" kind:is_null | |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Attachment: Encrypted zip file with payment-related lure
#Detects messages containing zip file attachments with payment-themed content that reference encrypted files, passwords, and payment details. The rule looks for specific patterns indicating the attachment is encrypted and contains payment-related information, commonly used to evade security scanning by requiring manual extraction.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud, Malware/Ransomware |
| Tactics and techniques | Encryption, Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and length(attachments) > 0
// 3 instances of zip/encrypted/payment information
and 3 of (
regex.icontains(body.current_thread.text, 'zip file.{1,50}encrypted'),
regex.icontains(body.current_thread.text, 'attachment.{1,30}encrypted'),
regex.icontains(body.current_thread.text,
'password.{1,5}is.{1,5}[A-Z0-9]{8,}'
),
regex.icontains(body.current_thread.text,
'details.{1,20}payment.{1,30}attach'
),
strings.icontains(subject.subject, "you have received"),
strings.icontains(subject.subject, "new debit"),
strings.icontains(subject.subject, "payment confirmation"),
strings.icontains(subject.subject, "invoice attached")
)
and (
// one attachment included and the file is a zip
attachments[0].file_extension == "zip"
and (
regex.icontains(attachments[0].file_name,
'payment|invoice|receipt|document|bank'
)
// long uppercase passwords
or regex.contains(body.current_thread.text, '[A-Z]{10,}')
)
)
Detection Logic
Scope: inbound message.
Detects messages containing zip file attachments with payment-themed content that reference encrypted files, passwords, and payment details. The rule looks for specific patterns indicating the attachment is encrypted and contains payment-related information, commonly used to evade security scanning by requiring manual extraction.
- inbound message
- length(attachments) > 0
at least 3 of:
- body.current_thread.text matches 'zip file.{1,50}encrypted'
- body.current_thread.text matches 'attachment.{1,30}encrypted'
- body.current_thread.text matches 'password.{1,5}is.{1,5}[A-Z0-9]{8,}'
- body.current_thread.text matches 'details.{1,20}payment.{1,30}attach'
- subject.subject contains 'you have received'
- subject.subject contains 'new debit'
- subject.subject contains 'payment confirmation'
- subject.subject contains 'invoice attached'
all of:
- attachments[0].file_extension is 'zip'
any of:
- attachments[0].file_name matches 'payment|invoice|receipt|document|bank'
- body.current_thread.text matches '[A-Z]{10,}'
Inspects: attachments[0].file_extension, attachments[0].file_name, body.current_thread.text, subject.subject, type.inbound. Sensors: regex.contains, regex.icontains, strings.icontains.
Indicators Matched (11)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | zip file.{1,50}encrypted |
regex.icontains | regex | attachment.{1,30}encrypted |
regex.icontains | regex | password.{1,5}is.{1,5}[A-Z0-9]{8,} |
regex.icontains | regex | details.{1,20}payment.{1,30}attach |
strings.icontains | substring | you have received |
strings.icontains | substring | new debit |
strings.icontains | substring | payment confirmation |
strings.icontains | substring | invoice attached |
attachments[0].file_extension | equals | zip |
regex.icontains | regex | payment|invoice|receipt|document|bank |
regex.contains | regex | [A-Z]{10,} |
Stages and Predicates
Stage 1: mql_rule
and
or
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "new debit"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "attachment.{1,30}encrypted"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "invoice attached"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "invoice attached"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "invoice attached"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "new debit"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "details.{1,20}payment.{1,30}attach"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "invoice attached"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "invoice attached"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "invoice attached"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "new debit"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "password.{1,5}is.{1,5}[A-Z0-9]{8,}"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "new debit"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "new debit"
subject.subject contains "you have received"
and
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
and
subject.subject contains "invoice attached"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
and
subject.subject contains "invoice attached"
subject.subject contains "new debit"
subject.subject contains "you have received"
and
subject.subject contains "invoice attached"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
and
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
or
attachments[0].file_name regex_match "payment|invoice|receipt|document|bank"
body.current_thread.text regex_match "[A-Z]{10,}"
attachments length_compare "0"
attachments[0].file_extension eq "zip"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
attachments[0].file_extension | eq |
| field:"attachments[0].file_extension" kind:eq value:"zip" |
attachments[0].file_name | regex_match |
| field:"attachments[0].file_name" kind:regex_match |
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
subject.subject | contains |
| field:"subject.subject" kind:contains |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
BEC/Fraud: Fake investment outreach from suspicious TLD
#Detects unsolicited investment/funding outreach emails from suspicious TLDs. Targets mass-mailed spam campaigns offering business funding, capital allocation, and family office outreach.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// subject contains investment language
and (
strings.istarts_with(subject.base, 'financing for', 'investment into')
or strings.icontains(subject.base, "family office")
)
// financial body content
and (
any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "Financial Communications" and .confidence != "low"
)
or (
any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "B2B Cold Outreach" and .confidence != "low"
)
and regex.icontains(body.current_thread.text,
'funding',
'capital',
'\d{3}k',
'rates from \d+%',
'funded in \d+',
'family office'
)
)
)
// suspicious sender
and (
sender.email.domain.tld in $suspicious_tlds
or sender.email.domain.tld == "info"
)
Detection Logic
Scope: inbound message.
Detects unsolicited investment/funding outreach emails from suspicious TLDs. Targets mass-mailed spam campaigns offering business funding, capital allocation, and family office outreach.
- inbound message
any of:
subject.base starts with any of 2 patterns
financing forinvestment into
- subject.base contains 'family office'
any of:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Financial Communications" and .confidence != "low" )
all of:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "B2B Cold Outreach" and .confidence != "low" )
body.current_thread.text matches any of 6 patterns
fundingcapital\d{3}krates from \d+%funded in \d+family office
any of:
- sender.email.domain.tld in $suspicious_tlds
- sender.email.domain.tld is 'info'
Inspects: body.current_thread.text, sender.email.domain.tld, subject.base, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.icontains, strings.istarts_with. Reference lists: $suspicious_tlds.
Indicators Matched (12)
| Field | Match | Value |
|---|---|---|
strings.istarts_with | prefix | financing for |
strings.istarts_with | prefix | investment into |
strings.icontains | substring | family office |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Financial Communications |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | B2B Cold Outreach |
regex.icontains | regex | funding |
regex.icontains | regex | capital |
regex.icontains | regex | \d{3}k |
regex.icontains | regex | rates from \d+% |
regex.icontains | regex | funded in \d+ |
regex.icontains | regex | family office |
sender.email.domain.tld | equals | info |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
body.current_thread.text regex_match "\\d{3}k"
body.current_thread.text regex_match "capital"
body.current_thread.text regex_match "family office"
body.current_thread.text regex_match "funded in \\d+"
body.current_thread.text regex_match "funding"
body.current_thread.text regex_match "rates from \\d+%"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"B2B Cold Outreach\" and .confidence != \"low\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"Financial Communications\" and .confidence != \"low\"\n )"
or
sender.email.domain.tld eq "info"
sender.email.domain.tld macro "sender.email.domain.tld in suspicious_tlds"
or
subject.base contains "family office"
subject.base starts_with "financing for"
subject.base starts_with "investment into"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
sender.email.domain.tld | eq |
| field:"sender.email.domain.tld" kind:eq value:"info" |
subject.base | contains |
| field:"subject.base" kind:contains value:"family office" |
subject.base | starts_with |
| field:"subject.base" kind:starts_with |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
BEC/Fraud: Job scam fake thread or plaintext pivot to freemail
#Detects potential job scams using plaintext or fake threads attempting to pivot to a freemail address from an unsolicited sender.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Free email provider, Out of band pivot |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(ml.nlu_classifier(body.current_thread.text).entities,
.name in ("greeting", "salutation")
)
// most likely to occur in plain text
and (
body.html.raw is null
or
// HTML is not null but fake thread
(
subject.is_reply or subject.is_forward
)
and (
(length(headers.references) == 0 and headers.in_reply_to is null)
or headers.in_reply_to is null
)
)
and (
3 of (
any([subject.subject, body.current_thread.text],
regex.icontains(., '(full|part).time')
),
strings.ilike(body.current_thread.text, '*job*'),
regex.icontains(body.current_thread.text, '\bHR\b'),
strings.ilike(body.current_thread.text, '*manager*'),
strings.ilike(body.current_thread.text, '*commission*'),
strings.ilike(body.current_thread.text, '*hourly*'),
strings.ilike(body.current_thread.text, '*per hour*'),
strings.ilike(body.current_thread.text, '*prior experience*'),
strings.ilike(body.current_thread.text, '*company rep*'),
strings.ilike(body.current_thread.text, "100% legal")
)
or (
length(ml.nlu_classifier(body.current_thread.text).topics) == 1
and any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "Professional and Career Development"
and .confidence == "high"
)
and (
length(recipients.to) == 0
or all(recipients.to,
strings.ilike(.display_name, "Undisclosed?recipients")
)
)
)
)
// all attachments are images or there's no attachments
and (
(
length(attachments) > 0
and all(attachments, .file_type in $file_types_images)
)
or length(attachments) == 0
)
// there's an email in the body and it's a freemail
and any(regex.extract(body.current_thread.text,
"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
),
strings.parse_email(.full_match).domain.domain in $free_email_providers
or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
)
// and that email doesn't match the sender domain
and (
all(body.links, .href_url.domain.root_domain != sender.email.domain.domain)
or sender.email.domain.root_domain in $free_email_providers
)
Detection Logic
Scope: inbound message.
Detects potential job scams using plaintext or fake threads attempting to pivot to a freemail address from an unsolicited sender.
- inbound message
- any(ml.nlu_classifier(body.current_thread.text).entities, .name in ("greeting", "salutation") )
any of:
- body.html.raw is missing
all of:
any of:
- subject.is_reply
- subject.is_forward
any of:
all of:
- length(headers.references) == 0
- headers.in_reply_to is missing
- headers.in_reply_to is missing
any of:
at least 3 of:
- any([subject.subject, body.current_thread.text], regex.icontains(., '(full|part).time') )
- body.current_thread.text matches '*job*'
- body.current_thread.text matches '\\bHR\\b'
- body.current_thread.text matches '*manager*'
- body.current_thread.text matches '*commission*'
- body.current_thread.text matches '*hourly*'
- body.current_thread.text matches '*per hour*'
- body.current_thread.text matches '*prior experience*'
- body.current_thread.text matches '*company rep*'
- body.current_thread.text matches '100% legal'
all of:
- length(ml.nlu_classifier(body.current_thread.text).topics) == 1
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Professional and Career Development" and .confidence == "high" )
any of:
- length(recipients.to) == 0
all of
recipients.towhere:- .display_name matches 'Undisclosed?recipients'
any of:
all of:
- length(attachments) > 0
all of
attachmentswhere:- .file_type in $file_types_images
- length(attachments) == 0
- any(regex.extract(body.current_thread.text, "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" ), strings.parse_email(.full_match).domain.domain in $free_email_providers or strings.parse_email(.full_match).domain.root_domain in $free_email_providers )
any of:
all of
body.linkswhere:- .href_url.domain.root_domain is not sender.email.domain.domain
- sender.email.domain.root_domain in $free_email_providers
Inspects: attachments[].file_type, body.current_thread.text, body.html.raw, body.links, body.links[].href_url.domain.root_domain, headers.in_reply_to, headers.references, recipients.to, recipients.to[].display_name, sender.email.domain.domain, sender.email.domain.root_domain, subject.is_forward, subject.is_reply, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.extract, regex.icontains, strings.ilike, strings.parse_email. Reference lists: $file_types_images, $free_email_providers.
Indicators Matched (16)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).entities[].name | member | greeting |
ml.nlu_classifier(body.current_thread.text).entities[].name | member | salutation |
regex.icontains | regex | (full|part).time |
strings.ilike | substring | *job* |
regex.icontains | regex | \bHR\b |
strings.ilike | substring | *manager* |
strings.ilike | substring | *commission* |
strings.ilike | substring | *hourly* |
strings.ilike | substring | *per hour* |
strings.ilike | substring | *prior experience* |
strings.ilike | substring | *company rep* |
strings.ilike | substring | 100% legal |
4 more
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Professional and Career Development |
ml.nlu_classifier(body.current_thread.text).topics[].confidence | equals | high |
strings.ilike | substring | Undisclosed?recipients |
regex.extract | regex | [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,} |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
and
headers.in_reply_to is_null
headers.references length_compare "0"
headers.in_reply_to is_null
or
subject.is_forward eq "true"
subject.is_reply eq "true"
body.html.raw is_null
or
and
or
recipients.to length_compare "0"
macro "all(recipients.to,\n strings.ilike(.display_name, \"Undisclosed?recipients\")\n )"
length func_call "length(ml.nlu_classifier(body.current_thread.text).topics) == 1"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"Professional and Career Development\"\n and .confidence == \"high\"\n )"
macro "3 of (\n any([subject.subject, body.current_thread.text],\n regex.icontains(., '(full|part).time')\n ),\n strings.ilike(body.current_thread.text, '*job*'),\n regex.icontains(body.current_thread.text, '\\bHR\\b'),\n strings.ilike(body.current_thread.text, '*manager*'),\n strings.ilike(body.current_thread.text, '*commission*'),\n strings.ilike(body.current_thread.text, '*hourly*'),\n strings.ilike(body.current_thread.text, '*per hour*'),\n strings.ilike(body.current_thread.text, '*prior experience*'),\n strings.ilike(body.current_thread.text, '*company rep*'),\n strings.ilike(body.current_thread.text, \"100% legal\")\n )"
or
and
attachments length_compare "0"
macro "all(attachments, .file_type in $file_types_images)"
attachments length_compare "0"
or
sender.email.domain.root_domain macro "sender.email.domain.root_domain in free_email_providers"
macro "all(body.links, .href_url.domain.root_domain != sender.email.domain.domain)"
type.inbound eq "true"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name in (\"greeting\", \"salutation\")\n)"
macro "any(regex.extract(body.current_thread.text,\n \"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}\"\n ),\n strings.parse_email(.full_match).domain.domain in $free_email_providers\n or strings.parse_email(.full_match).domain.root_domain in $free_email_providers\n)"Indicators
These rows show field, operator, and value matches.
BEC: Financial fraud from newly registered sender domain
#Detects inbound messages from domains registered less than 30 days ago that exhibit business email compromise intent with high-confidence financial or payment topics. The message must also contain explicit banking details such as account and routing numbers, invoice references, or payment urgency language, and must either fail DMARC on a trusted domain or originate from an untrusted domain.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering, Spoofing |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and network.whois(sender.email.domain).days_old < 30
and any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec")
and (
any(ml.nlu_classifier(body.current_thread.text).topics,
.name in ("Financial Communications", "Payment Information")
and .confidence == "high"
)
)
and (
(
regex.icontains(body.current_thread.text,
'account\s*(?:number|num|no\.?)\s*:?\s*\d{5,}'
)
and regex.icontains(body.current_thread.text,
'(?:wire\s*)?routing\s*(?:number|num|no\.?)\s*:?\s*\d{5,}'
)
)
or regex.icontains(body.current_thread.text,
'invoice\s*(?:#|number|num|no\.?)\s*:?\s*[A-Z0-9-]{3,}',
'per\s+\w+.{0,5}s\s+request'
)
or strings.icontains(body.current_thread.text,
'due upon receipt',
'confirm receipt of invoice',
'see attached invoice'
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and not (
sender.email.domain.root_domain in $high_trust_sender_root_domains
and coalesce(headers.auth_summary.dmarc.pass, false)
)
Detection Logic
Scope: inbound message.
Detects inbound messages from domains registered less than 30 days ago that exhibit business email compromise intent with high-confidence financial or payment topics. The message must also contain explicit banking details such as account and routing numbers, invoice references, or payment urgency language, and must either fail DMARC on a trusted domain or originate from an untrusted domain.
- inbound message
- network.whois(sender.email.domain).days_old < 30
- any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec")
- ( any(ml.nlu_classifier(body.current_thread.text).topics, .name in ("Financial Communications", "Payment Information") and .confidence == "high" ) )
any of:
all of:
- body.current_thread.text matches 'account\\s*(?:number|num|no\\.?)\\s*:?\\s*\\d{5,}'
- body.current_thread.text matches '(?:wire\\s*)?routing\\s*(?:number|num|no\\.?)\\s*:?\\s*\\d{5,}'
body.current_thread.text matches any of 2 patterns
invoice\s*(?:#|number|num|no\.?)\s*:?\s*[A-Z0-9-]{3,}per\s+\w+.{0,5}s\s+request
body.current_thread.text contains any of 3 patterns
due upon receiptconfirm receipt of invoicesee attached invoice
not:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
- coalesce(headers.auth_summary.dmarc.pass, false)
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, sender.email.domain, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, network.whois, regex.icontains, strings.icontains. Reference lists: $high_trust_sender_root_domains.
Indicators Matched (11)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | bec |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Financial Communications |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Payment Information |
ml.nlu_classifier(body.current_thread.text).topics[].confidence | equals | high |
regex.icontains | regex | account\s*(?:number|num|no\.?)\s*:?\s*\d{5,} |
regex.icontains | regex | (?:wire\s*)?routing\s*(?:number|num|no\.?)\s*:?\s*\d{5,} |
regex.icontains | regex | invoice\s*(?:#|number|num|no\.?)\s*:?\s*[A-Z0-9-]{3,} |
regex.icontains | regex | per\s+\w+.{0,5}s\s+request |
strings.icontains | substring | due upon receipt |
strings.icontains | substring | confirm receipt of invoice |
strings.icontains | substring | see attached invoice |
Stages and Predicates
Stage 1: mql_rule
and
or
and
body.current_thread.text regex_match "(?:wire\\s*)?routing\\s*(?:number|num|no\\.?)\\s*:?\\s*\\d{5,}"
body.current_thread.text regex_match "account\\s*(?:number|num|no\\.?)\\s*:?\\s*\\d{5,}"
body.current_thread.text contains "confirm receipt of invoice"
body.current_thread.text contains "due upon receipt"
body.current_thread.text contains "see attached invoice"
body.current_thread.text regex_match "invoice\\s*(?:#|number|num|no\\.?)\\s*:?\\s*[A-Z0-9-]{3,}"
body.current_thread.text regex_match "per\\s+\\w+.{0,5}s\\s+request"
not
and
headers.auth_summary.dmarc.pass eq "true"
headers.auth_summary.dmarc.pass is_not_null
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
network.whois func_call "network.whois(sender.email.domain).days_old < 30"
type.inbound eq "true"
macro "(\n any(ml.nlu_classifier(body.current_thread.text).topics,\n .name in (\"Financial Communications\", \"Payment Information\")\n and .confidence == \"high\"\n )\n)"
macro "any(ml.nlu_classifier(body.current_thread.text).intents, .name == \"bec\")"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | contains |
| field:"body.current_thread.text" kind:contains |
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
headers.auth_summary.dmarc.pass | is_not_null | excludes:headers.auth_summary.dmarc.pass |
Body: AI-generated invoice template artifacts
#Flags inbound messages where NLU classification of the thread text indicates medium or high confidence credential theft or BEC intent, and the message HTML contains comment artifacts characteristic of AI-generated invoice/billing templates (e.g. 'PDF icon', 'File row', 'Billing Table', 'CTA Button'). Messages from highly trusted sender domains are excluded unless they fail DMARC authentication.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, BEC/Fraud |
| Tactics and techniques | Social engineering, Spoofing |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("cred_theft", "bec") and .confidence in ("medium", "high")
)
// templated ai-generated comments
and any(html.xpath(body.html, '//comment()').nodes,
regex.icontains(.raw,
'PDF icon|File row|Status \+ Reference|Billing Table|Invoice Info|CTA Button'
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and not (
sender.email.domain.root_domain in $high_trust_sender_root_domains
and coalesce(headers.auth_summary.dmarc.pass, false)
)
Detection Logic
Scope: inbound message.
Flags inbound messages where NLU classification of the thread text indicates medium or high confidence credential theft or BEC intent, and the message HTML contains comment artifacts characteristic of AI-generated invoice/billing templates (e.g. 'PDF icon', 'File row', 'Billing Table', 'CTA Button'). Messages from highly trusted sender domains are excluded unless they fail DMARC authentication.
- inbound message
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("cred_theft", "bec") and .confidence in ("medium", "high") )
- any(html.xpath(body.html, '//comment()').nodes, regex.icontains(.raw, 'PDF icon|File row|Status \+ Reference|Billing Table|Invoice Info|CTA Button' ) )
not:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
- coalesce(headers.auth_summary.dmarc.pass, false)
Inspects: body.current_thread.text, body.html, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, type.inbound. Sensors: html.xpath, ml.nlu_classifier, regex.icontains. Reference lists: $high_trust_sender_root_domains.
Indicators Matched (5)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | member | cred_theft |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | medium |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | high |
regex.icontains | regex | PDF icon|File row|Status \+ Reference|Billing Table|Invoice Info|CTA Button |
Stages and Predicates
Stage 1: mql_rule
and
not
and
headers.auth_summary.dmarc.pass eq "true"
headers.auth_summary.dmarc.pass is_not_null
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
type.inbound eq "true"
macro "any(html.xpath(body.html, '//comment()').nodes,\n regex.icontains(.raw,\n 'PDF icon|File row|Status \\+ Reference|Billing Table|Invoice Info|CTA Button'\n )\n)"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"cred_theft\", \"bec\") and .confidence in (\"medium\", \"high\")\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
headers.auth_summary.dmarc.pass | is_not_null | excludes:headers.auth_summary.dmarc.pass |
Body: CSS clamp() font obfuscation
#Detects inbound messages where the HTML body (including HTML content within .eml attachments) uses CSS clamp() with a font-size or line-height minimum bound of zero or a negative value. This technique renders text invisible or unreadable to recipients while remaining present in the underlying markup, a method commonly used to hide malicious content or evade text-based detection engines.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
(
regex.icontains(body.html.raw,
'(?:font-size|line-height):\s*clamp\s*\(\s*(?:-\d+|0)(?:px|em|rem|pt)?,'
)
)
or any(attachments,
(.content_type == "message/rfc822" or .file_extension =~ "eml")
and regex.icontains(file.parse_eml(.).body.html.raw,
'(?:font-size|line-height):\s*clamp\s*\(\s*(?:-\d+|0)(?:px|em|rem|pt)?,'
)
)
)
Detection Logic
Scope: inbound message.
Detects inbound messages where the HTML body (including HTML content within .eml attachments) uses CSS clamp() with a font-size or line-height minimum bound of zero or a negative value. This technique renders text invisible or unreadable to recipients while remaining present in the underlying markup, a method commonly used to hide malicious content or evade text-based detection engines.
- inbound message
any of:
- body.html.raw matches '(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,'
any of
attachmentswhere all hold:any of:
- .content_type is 'message/rfc822'
- .file_extension is 'eml'
- regex.icontains(file.parse_eml(.).body.html.raw, '(?:font-size|line-height):\s*clamp\s*\(\s*(?:-\d+|0)(?:px|em|rem|pt)?,' )
Inspects: attachments[].content_type, attachments[].file_extension, body.html.raw, type.inbound. Sensors: file.parse_eml, regex.icontains.
Indicators Matched (3)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | (?:font-size|line-height):\s*clamp\s*\(\s*(?:-\d+|0)(?:px|em|rem|pt)?, |
attachments[].content_type | equals | message/rfc822 |
attachments[].file_extension | equals | eml |
Stages and Predicates
Stage 1: mql_rule
and
or
any(attachments)
and
or
attachments.content_type eq "message/rfc822"
attachments.file_extension eq "eml"
regex.icontains func_call "regex.icontains(file.parse_eml(.).body.html.raw,\n '(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,'\n )"
body.html.raw regex_match "(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | regex_match |
| field:"body.html.raw" kind:regex_match value:"(?:font-size|line-height):\s*clamp\s*(\s*(?:-\d+|0)(?:px|em|rem|pt)?," |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: CSS Hidden text via clip-path
#Detects inbound messages containing a div styled with 'clip-path: inset(100%)', a CSS technique used to visually hide substantial blocks of text (over 150 characters) from the recipient while keeping it present in the underlying HTML. This method is commonly used to evade content-based detection engines by hiding filler or unrelated text within the message body.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Spam, Credential Phishing |
| Tactics and techniques | Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodes,
regex.icontains(.raw, 'clip-path:\s*inset\(\s*100%')
and length(.inner_text) > 150
)
Detection Logic
Scope: inbound message.
Detects inbound messages containing a div styled with 'clip-path: inset(100%)', a CSS technique used to visually hide substantial blocks of text (over 150 characters) from the recipient while keeping it present in the underlying HTML. This method is commonly used to evade content-based detection engines by hiding filler or unrelated text within the message body.
- inbound message
- any(html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodes, regex.icontains(.raw, 'clip-path:\s*inset\(\s*100%') and length(.inner_text) > 150 )
Inspects: body.html, type.inbound. Sensors: html.xpath, regex.icontains.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | clip-path:\s*inset\(\s*100% |
Stages and Predicates
Stage 1: mql_rule
and
type.inbound eq "true"
macro "any(html.xpath(body.html, '//div[contains(@style,\"clip-path\")]').nodes,\n regex.icontains(.raw, 'clip-path:\\s*inset\\(\\s*100%')\n and length(.inner_text) > 150\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: CSS Hidden text via table-column
#Detects inbound messages containing elements styled with 'display: table-column' combined with a height or width of zero, effectively hiding the element from visual rendering. The rule flags cases where the hidden element contains more than 100 non-whitespace characters of inner text, a technique commonly used to conceal content from human recipients while still embedding it in the DOM to evade text-based or visual detection systems.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, Spam |
| Tactics and techniques | Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(html.xpath(body.html, '//*[contains(@style,"table-column")]').nodes,
regex.icontains(.raw, 'display\s*:\s*table-column')
and (
regex.icontains(.raw, '[;"\s]height\s*:\s*0')
or regex.icontains(.raw, '[;"\s]width\s*:\s*0')
)
and regex.icount(.inner_text, '\S') > 100
)
Detection Logic
Scope: inbound message.
Detects inbound messages containing elements styled with 'display: table-column' combined with a height or width of zero, effectively hiding the element from visual rendering. The rule flags cases where the hidden element contains more than 100 non-whitespace characters of inner text, a technique commonly used to conceal content from human recipients while still embedding it in the DOM to evade text-based or visual detection systems.
- inbound message
- any(html.xpath(body.html, '//*[contains(@style,"table-column")]').nodes, regex.icontains(.raw, 'display\s*:\s*table-column') and ( regex.icontains(.raw, '[;"\s]height\s*:\s*0') or regex.icontains(.raw, '[;"\s]width\s*:\s*0') ) and regex.icount(.inner_text, '\S') > 100 )
Inspects: body.html, type.inbound. Sensors: html.xpath, regex.icontains, regex.icount.
Indicators Matched (4)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | display\s*:\s*table-column |
regex.icontains | regex | [;"\s]height\s*:\s*0 |
regex.icontains | regex | [;"\s]width\s*:\s*0 |
regex.icount | regex | \S |
Stages and Predicates
Stage 1: mql_rule
and
type.inbound eq "true"
macro "any(html.xpath(body.html, '//*[contains(@style,\"table-column\")]').nodes,\n regex.icontains(.raw, 'display\\s*:\\s*table-column')\n and (\n regex.icontains(.raw, '[;\"\\s]height\\s*:\\s*0')\n or regex.icontains(.raw, '[;\"\\s]width\\s*:\\s*0')\n )\n and regex.icount(.inner_text, '\\S') > 100\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: CSS zero-value calc() obfuscation
#Detects inbound messages containing HTML where a CSS calc() expression subtracts an identical value and unit from itself (e.g., calc(100px - 100px)), always resolving to zero. This pattern is commonly used to hide or collapse content from view while keeping it present in the underlying HTML, a technique often leveraged to evade text-based detection or conceal malicious content from recipients.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, Spam |
| Tactics and techniques | Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(regex.iextract(body.html.raw,
'calc\(\s*(?P<n1>\d+(?:\.\d+)?)(?P<u1>px|vw|vh|em|rem|%)\s*-\s*(?P<n2>\d+(?:\.\d+)?)(?P<u2>px|vw|vh|em|rem|%)\s*\)'
),
.named_groups["n1"] == .named_groups["n2"]
and .named_groups["u1"] == .named_groups["u2"]
)
Detection Logic
Scope: inbound message.
Detects inbound messages containing HTML where a CSS calc() expression subtracts an identical value and unit from itself (e.g., calc(100px - 100px)), always resolving to zero. This pattern is commonly used to hide or collapse content from view while keeping it present in the underlying HTML, a technique often leveraged to evade text-based detection or conceal malicious content from recipients.
- inbound message
- any(regex.iextract(body.html.raw, 'calc\(\s*(?P<n1>\d+(?:\.\d+)?)(?P<u1>px|vw|vh|em|rem|%)\s*-\s*(?P<n2>\d+(?:\.\d+)?)(?P<u2>px|vw|vh|em|rem|%)\s*\)' ), .named_groups["n1"] == .named_groups["n2"] and .named_groups["u1"] == .named_groups["u2"] )
Inspects: body.html.raw, type.inbound. Sensors: regex.iextract.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
regex.iextract | regex | calc\(\s*(?P<n1>\d+(?:\.\d+)?)(?P<u1>px|vw|vh|em|rem|%)\s*-\s*(?P<n2>\d+(?:\.\d+)?)(?P<u2>px|vw|vh|em|rem|%)\s*\) |
Stages and Predicates
Stage 1: mql_rule
and
type.inbound eq "true"
macro "any(regex.iextract(body.html.raw,\n 'calc\\(\\s*(?P<n1>\\d+(?:\\.\\d+)?)(?P<u1>px|vw|vh|em|rem|%)\\s*-\\s*(?P<n2>\\d+(?:\\.\\d+)?)(?P<u2>px|vw|vh|em|rem|%)\\s*\\)'\n ),\n .named_groups[\"n1\"] == .named_groups[\"n2\"]\n and .named_groups[\"u1\"] == .named_groups[\"u2\"]\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: Fake secure email portal with HTML obfuscation
#Detects inbound messages with empty subjects impersonating a secure email portal, identified through multiple indicators including hidden HTML characters used to obfuscate the sender address, recipient domain echoed back as a portal sender, template typos, or frozen tracking links associated with known secure messaging infrastructure abuse.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Social engineering, Spoofing |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and subject.base == ""
and strings.icontains(body.current_thread.text, "Secure Emails")
and strings.icontains(body.current_thread.text, "Title:")
and (
// hidden-@ HTML obfuscation
regex.icontains(body.html.raw, '<font[^>]+display\s*:\s*none[^>]*>@</font>')
// recipient root domain echoed back as a portal sender
or any(recipients.to,
strings.icontains(body.current_thread.text,
strings.concat("acts@", .email.domain.root_domain)
)
)
// template typo
or strings.icontains(body.current_thread.text, "commuication portal")
// frozen crId or linkprotect.cudasvc.com inner target
or any(body.links,
.href_url.domain.domain == "links.us1.defend.egress.com"
and (
strings.icontains(.href_url.query_params,
"crId=6a17340ad2523c97775fed21"
)
or strings.icontains(.href_url.query_params,
"OriginalLink=linkprotect.cudasvc.com"
)
)
)
)
Detection Logic
Scope: inbound message.
Detects inbound messages with empty subjects impersonating a secure email portal, identified through multiple indicators including hidden HTML characters used to obfuscate the sender address, recipient domain echoed back as a portal sender, template typos, or frozen tracking links associated with known secure messaging infrastructure abuse.
- inbound message
- subject.base is ''
- body.current_thread.text contains 'Secure Emails'
- body.current_thread.text contains 'Title:'
any of:
- body.html.raw matches '<font[^>]+display\\s*:\\s*none[^>]*>@</font>'
any of
recipients.towhere:- strings.icontains(body.current_thread.text, strings.concat("acts@", .email.domain.root_domain) )
- body.current_thread.text contains 'commuication portal'
any of
body.linkswhere all hold:- .href_url.domain.domain is 'links.us1.defend.egress.com'
any of:
- .href_url.query_params contains 'crId=6a17340ad2523c97775fed21'
- .href_url.query_params contains 'OriginalLink=linkprotect.cudasvc.com'
Inspects: body.current_thread.text, body.html.raw, body.links, body.links[].href_url.domain.domain, body.links[].href_url.query_params, recipients.to, recipients.to[].email.domain.root_domain, subject.base, type.inbound. Sensors: regex.icontains, strings.concat, strings.icontains.
Indicators Matched (8)
| Field | Match | Value |
|---|---|---|
subject.base | equals | |
strings.icontains | substring | Secure Emails |
strings.icontains | substring | Title: |
regex.icontains | regex | <font[^>]+display\s*:\s*none[^>]*>@</font> |
strings.icontains | substring | commuication portal |
body.links[].href_url.domain.domain | equals | links.us1.defend.egress.com |
strings.icontains | substring | crId=6a17340ad2523c97775fed21 |
strings.icontains | substring | OriginalLink=linkprotect.cudasvc.com |
Stages and Predicates
Stage 1: mql_rule
and
or
any(body.links)
and
or
body.links.href_url.query_params contains "OriginalLink=linkprotect.cudasvc.com"
body.links.href_url.query_params contains "crId=6a17340ad2523c97775fed21"
body.links.href_url.domain.domain eq "links.us1.defend.egress.com"
any(recipients.to)
strings.icontains func_call "strings.icontains(body.current_thread.text,\n strings.concat(\"acts@\", .email.domain.root_domain)\n )"
body.current_thread.text contains "commuication portal"
body.html.raw regex_match "<font[^>]+display\\s*:\\s*none[^>]*>@</font>"
body.current_thread.text contains "Secure Emails"
body.current_thread.text contains "Title:"
subject.base eq ""
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | contains |
| field:"body.current_thread.text" kind:contains |
body.html.raw | regex_match |
| field:"body.html.raw" kind:regex_match value:"<font[^>]+display\s*:\s*none[^>]*>@</font>" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: HTML whitespace stuffing with short initial message
#Detects messages that uses HTML-based whitespace padding (repeated br tags, p-nbsp blocks, or div-br wrappers) to push content below the visible fold.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// not a legitimate thread reply or is indicative of self sender
and (
(length(headers.references) == 0 and headers.in_reply_to is null)
or (
length(recipients.to) == 1
and length(recipients.cc) == 0
and sender.email.email == recipients.to[0].email.email
)
)
// whitespace-stuffed credphish targets single recipients
and length(recipients.to) == 1
and length(recipients.cc) == 0
and length(recipients.bcc) == 0
// short lure
and length(body.current_thread.text) < 2000
// HTML whitespace stuffing
and (
regex.icontains(body.html.raw,
'(?:</?br\s*/?\s*>\s*){30,}',
'(?:<p>\s*(?:&nbsp;|&#160;)\s*</p>\s*){10,}',
'(?:<div[^>]*>\s*<br\s*/?\s*>\s*</div>\s*){20,}'
)
or (
regex.icontains(body.html.raw,
'(?:<p[^>]*>\s*<o:p>\s*(?:&nbsp;|&#160;)\s*</o:p>\s*</p>\s*){10,}',
'(?:<p[^>]*>\s*(?:&nbsp;|&#160;)\s*</p>\s*){30,}'
)
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("cred_theft", "bec")
)
or any(body.current_thread.links,
strings.ends_with(.href_url.path, 'php')
)
)
)
)
// low word count excludes legitimate long threads
and regex.count(body.html.display_text, '\S+') < 3000
// visible link in current thread pointing to external domain
and any(body.current_thread.links,
.href_url.domain.root_domain != sender.email.domain.root_domain
and .href_url.domain.valid
and .href_url.scheme in ("https", "http")
and .visible == true
)
// credential phishing has few visible links - newsletters have many
and length(filter(body.current_thread.links,
.href_url.domain.valid
and .href_url.scheme in ("https", "http")
and .visible == true
)
) < 10
// negate high trust senders that pass auth
and not (
sender.email.domain.root_domain in $high_trust_sender_root_domains
and coalesce(headers.auth_summary.dmarc.pass, false)
)
// negate authenticated senders with unsubscribe mechanism (marketing)
and not (
coalesce(headers.auth_summary.dmarc.pass, false)
and any(body.current_thread.links,
strings.icontains(.display_text, "unsubscribe")
or strings.icontains(.href_url.path, "unsubscribe")
)
)
Detection Logic
Scope: inbound message.
Detects messages that uses HTML-based whitespace padding (repeated br tags, p-nbsp blocks, or div-br wrappers) to push content below the visible fold.
- inbound message
any of:
all of:
- length(headers.references) == 0
- headers.in_reply_to is missing
all of:
- length(recipients.to) == 1
- length(recipients.cc) == 0
- sender.email.email is recipients.to[0].email.email
- length(recipients.to) == 1
- length(recipients.cc) == 0
- length(recipients.bcc) == 0
- length(body.current_thread.text) < 2000
any of:
body.html.raw matches any of 3 patterns
(?:</?br\s*/?\s*>\s*){30,}(?:<p>\s*(?:&nbsp;|&#160;)\s*</p>\s*){10,}(?:<div[^>]*>\s*<br\s*/?\s*>\s*</div>\s*){20,}
all of:
body.html.raw matches any of 2 patterns
(?:<p[^>]*>\s*<o:p>\s*(?:&nbsp;|&#160;)\s*</o:p>\s*</p>\s*){10,}(?:<p[^>]*>\s*(?:&nbsp;|&#160;)\s*</p>\s*){30,}
any of:
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("cred_theft", "bec") )
any of
body.current_thread.linkswhere:- .href_url.path ends with 'php'
- regex.count(body.html.display_text, '\S+') < 3000
any of
body.current_thread.linkswhere all hold:- .href_url.domain.root_domain is not sender.email.domain.root_domain
- .href_url.domain.valid
- .href_url.scheme in ('https', 'http')
- .visible is True
- length(filter(body.current_thread.links, .href_url.domain.valid and .href_url.scheme in ("https", "http") and .visible == true ) ) < 10
not:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
- coalesce(headers.auth_summary.dmarc.pass, false)
not:
all of:
- coalesce(headers.auth_summary.dmarc.pass, false)
any of
body.current_thread.linkswhere any holds:- .display_text contains 'unsubscribe'
- .href_url.path contains 'unsubscribe'
Inspects: body.current_thread.links, body.current_thread.links[].display_text, body.current_thread.links[].href_url.domain.root_domain, body.current_thread.links[].href_url.domain.valid, body.current_thread.links[].href_url.path, body.current_thread.links[].href_url.scheme, body.current_thread.links[].visible, body.current_thread.text, body.html.display_text, body.html.raw, headers.auth_summary.dmarc.pass, headers.in_reply_to, headers.references, recipients.bcc, recipients.cc, recipients.to, recipients.to[0].email.email, sender.email.domain.root_domain, sender.email.email, type.inbound. Sensors: ml.nlu_classifier, regex.count, regex.icontains, strings.ends_with, strings.icontains. Reference lists: $high_trust_sender_root_domains.
Indicators Matched (11)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | (?:</?br\s*/?\s*>\s*){30,} |
regex.icontains | regex | (?:<p>\s*(?:&nbsp;|&#160;)\s*</p>\s*){10,} |
regex.icontains | regex | (?:<div[^>]*>\s*<br\s*/?\s*>\s*</div>\s*){20,} |
regex.icontains | regex | (?:<p[^>]*>\s*<o:p>\s*(?:&nbsp;|&#160;)\s*</o:p>\s*</p>\s*){10,} |
regex.icontains | regex | (?:<p[^>]*>\s*(?:&nbsp;|&#160;)\s*</p>\s*){30,} |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | cred_theft |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
strings.ends_with | suffix | php |
regex.count | regex | \S+ |
body.current_thread.links[].href_url.scheme | member | https |
body.current_thread.links[].href_url.scheme | member | http |
Stages and Predicates
Stage 1: mql_rule
and
not
and
any(body.current_thread.links)
or
body.current_thread.links.display_text contains "unsubscribe"
body.current_thread.links.href_url.path contains "unsubscribe"
headers.auth_summary.dmarc.pass eq "true"
headers.auth_summary.dmarc.pass is_not_null
or
and
or
any(body.current_thread.links)
body.current_thread.links.href_url.path ends_with "php"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"cred_theft\", \"bec\")\n )"
or
body.html.raw regex_match "(?:<p[^>]*>\\s*(?:&nbsp;|&#160;)\\s*</p>\\s*){30,}"
body.html.raw regex_match "(?:<p[^>]*>\\s*<o:p>\\s*(?:&nbsp;|&#160;)\\s*</o:p>\\s*</p>\\s*){10,}"
body.html.raw regex_match "(?:</?br\\s*/?\\s*>\\s*){30,}"
body.html.raw regex_match "(?:<div[^>]*>\\s*<br\\s*/?\\s*>\\s*</div>\\s*){20,}"
body.html.raw regex_match "(?:<p>\\s*(?:&nbsp;|&#160;)\\s*</p>\\s*){10,}"
any(body.current_thread.links)
and
body.current_thread.links.href_url.domain.root_domain cross_field_compare "sender.email.domain.root_domain"
body.current_thread.links.href_url.domain.valid eq "true"
body.current_thread.links.href_url.scheme in ["http", "https"]
body.current_thread.links.visible eq "true"
not
and
headers.auth_summary.dmarc.pass eq "true"
headers.auth_summary.dmarc.pass is_not_null
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
or
and
headers.in_reply_to is_null
headers.references length_compare "0"
and
recipients.cc length_compare "0"
recipients.to length_compare "1"
sender.email.email cross_field_compare "recipients.to[0].email.email"
body.current_thread.text length_compare "2000"
length func_call "length(filter(body.current_thread.links,\n .href_url.domain.valid\n and .href_url.scheme in (\"https\", \"http\")\n and .visible == true\n )\n) < 10"
recipients.bcc length_compare "0"
recipients.cc length_compare "0"
recipients.to length_compare "1"
regex.count func_call "regex.count(body.html.display_text, '\\S+') < 3000"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | regex_match |
| field:"body.html.raw" kind:regex_match |
headers.in_reply_to | is_null | field:"headers.in_reply_to" kind:is_null | |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
body.current_thread.links | array_any | excludes:body.current_thread.links | |
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
headers.auth_summary.dmarc.pass | is_not_null | excludes:headers.auth_summary.dmarc.pass |
Body: Invisible Unicode obfuscation student loan callback phishing
#Detects messages containing clusters of Unicode zero-width and invisible characters (such as LRM, RLM, zero-width space, BOM, and directional isolates) interspersed within digit sequences and body content matching 'student loan' patterns. This technique is used to obscure text from security filters while remaining visually coherent to recipients.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud, Credential Phishing, Spam |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and regex.contains(body.html.raw,
'(\x{2065}|\x{200E}|\x{200F}|\x{2066}|\x{2067}|\x{2068}|\x{2069}|\x{200B}|\x{200C}|\x{200D}|\x{FEFF}){3}'
)
and regex.contains(body.html.raw,
'\d[\x{200E}\x{200F}\x{200B}\x{200C}\x{200D}\x{2065}\x{FEFF}]{1,6}\d'
)
and regex.icontains(body.html.raw,
's.{0,6}t.{0,6}u.{0,6}d.{0,6}e.{0,6}n.{0,6}t.{0,10}l.{0,6}o.{0,6}a.{0,6}n'
)
Detection Logic
Scope: inbound message.
Detects messages containing clusters of Unicode zero-width and invisible characters (such as LRM, RLM, zero-width space, BOM, and directional isolates) interspersed within digit sequences and body content matching 'student loan' patterns. This technique is used to obscure text from security filters while remaining visually coherent to recipients.
- inbound message
- body.html.raw matches '(\\x{2065}|\\x{200E}|\\x{200F}|\\x{2066}|\\x{2067}|\\x{2068}|\\x{2069}|\\x{200B}|\\x{200C}|\\x{200D}|\\x{FEFF}){3}'
- body.html.raw matches '\\d[\\x{200E}\\x{200F}\\x{200B}\\x{200C}\\x{200D}\\x{2065}\\x{FEFF}]{1,6}\\d'
- body.html.raw matches 's.{0,6}t.{0,6}u.{0,6}d.{0,6}e.{0,6}n.{0,6}t.{0,10}l.{0,6}o.{0,6}a.{0,6}n'
Inspects: body.html.raw, type.inbound. Sensors: regex.contains, regex.icontains.
Indicators Matched (3)
| Field | Match | Value |
|---|---|---|
regex.contains | regex | (\x{2065}|\x{200E}|\x{200F}|\x{2066}|\x{2067}|\x{2068}|\x{2069}|\x{200B}|\x{200C}|\x{200D}|\x{FEFF}){3} |
regex.contains | regex | \d[\x{200E}\x{200F}\x{200B}\x{200C}\x{200D}\x{2065}\x{FEFF}]{1,6}\d |
regex.icontains | regex | s.{0,6}t.{0,6}u.{0,6}d.{0,6}e.{0,6}n.{0,6}t.{0,10}l.{0,6}o.{0,6}a.{0,6}n |
Stages and Predicates
Stage 1: mql_rule
and
body.html.raw regex_match "(\\x{2065}|\\x{200E}|\\x{200F}|\\x{2066}|\\x{2067}|\\x{2068}|\\x{2069}|\\x{200B}|\\x{200C}|\\x{200D}|\\x{FEFF}){3}"
body.html.raw regex_match "\\d[\\x{200E}\\x{200F}\\x{200B}\\x{200C}\\x{200D}\\x{2065}\\x{FEFF}]{1,6}\\d"
body.html.raw regex_match "s.{0,6}t.{0,6}u.{0,6}d.{0,6}e.{0,6}n.{0,6}t.{0,10}l.{0,6}o.{0,6}a.{0,6}n"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | regex_match |
| field:"body.html.raw" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: Suspicious date format
#Detects messages containing strage date formats observed in phishing emails.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Spoofing, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and regex.icontains(body.current_thread.text,
'Date:\s(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s(?:January|February|March|April|May|June|July|August|September|October|November|December)\s202(?:5|6|7|8|9)'
)
Detection Logic
Scope: inbound message.
Detects messages containing strage date formats observed in phishing emails.
- inbound message
- body.current_thread.text matches 'Date:\\s(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\\s(?:January|February|March|April|May|June|July|August|September|October|November|December)\\s202(?:5|6|7|8|9)'
Inspects: body.current_thread.text, type.inbound. Sensors: regex.icontains.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | Date:\s(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s(?:January|February|March|April|May|June|July|August|September|October|November|December)\s202(?:5|6|7|8|9) |
Stages and Predicates
Stage 1: mql_rule
and
body.current_thread.text regex_match "Date:\\s(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\\s(?:January|February|March|April|May|June|July|August|September|October|November|December)\\s202(?:5|6|7|8|9)"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"Date:\s(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s(?:January|February|March|April|May|June|July|August|September|October|November|December)\s202(?:5|6|7|8|9)" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: Suspicious table template fingerprint
#Detects messages matching a specific HTML template fingerprint characterized by a table containing both 'Important' and 'Company' text nodes. This pattern is associated with a known malicious message template used to deceive recipients.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Social engineering, Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// table template fingerprint containing "important" and "company"
and any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes,
.display_text == "Important"
)
and any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes,
.display_text == "Company"
)
Detection Logic
Scope: inbound message.
Detects messages matching a specific HTML template fingerprint characterized by a table containing both 'Important' and 'Company' text nodes. This pattern is associated with a known malicious message template used to deceive recipients.
- inbound message
- any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes, .display_text == "Important" )
- any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes, .display_text == "Company" )
Inspects: body.html, type.inbound. Sensors: html.xpath.
Indicators Matched (2)
| Field | Match | Value |
|---|---|---|
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes[].display_text | equals | Important |
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes[].display_text | equals | Company |
Stages and Predicates
Stage 1: mql_rule
and
type.inbound eq "true"
macro "any(html.xpath(body.html, '//td[contains(@style, \"background-color\")]').nodes,\n .display_text == \"Company\"\n)"
macro "any(html.xpath(body.html, '//td[contains(@style, \"background-color\")]').nodes,\n .display_text == \"Important\"\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: Yellow highlighted text markers
#Detects messages containing multiple HTML span elements with yellow background highlighting (rgb(255, 241, 0)) and data-markjs attributes, potentially indicating evasion techniques through visual markup manipulation.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, BEC/Fraud |
| Tactics and techniques | Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and regex.icount(body.html.raw, 'data-markjs="true"') >= 2
and strings.icontains(body.html.raw, 'background-color: rgb(255, 241, 0)')
Detection Logic
Scope: inbound message.
Detects messages containing multiple HTML span elements with yellow background highlighting (rgb(255, 241, 0)) and data-markjs attributes, potentially indicating evasion techniques through visual markup manipulation.
- inbound message
- regex.icount(body.html.raw, 'data-markjs="true"') >= 2
- body.html.raw contains 'background-color: rgb(255, 241, 0)'
Inspects: body.html.raw, type.inbound. Sensors: regex.icount, strings.icontains.
Indicators Matched (2)
| Field | Match | Value |
|---|---|---|
regex.icount | regex | data-markjs="true" |
strings.icontains | substring | background-color: rgb(255, 241, 0) |
Stages and Predicates
Stage 1: mql_rule
and
body.html.raw contains "background-color: rgb(255, 241, 0)"
regex.icount func_call "regex.icount(body.html.raw, 'data-markjs=\"true\"') >= 2"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | contains |
| field:"body.html.raw" kind:contains value:"background-color: rgb(255, 241, 0)" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Brand impersonation: Microsoft logo or suspicious language with open redirect
#Message contains a Microsoft logo or suspicious terms and use of an open redirect. This has been exploited in the wild to impersonate Microsoft.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Impersonation: Brand, Open redirect, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (length(attachments) < 5 or length(body.links) < 10)
// Microsoft logo
and (
any(attachments,
.file_type in $file_types_images
and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft"))
)
or any(attachments,
.file_type in $file_types_images
and (
any(file.explode(.),
2 of (
strings.ilike(.scan.ocr.raw, "*password*"),
strings.ilike(.scan.ocr.raw, "*unread messages*"),
strings.ilike(.scan.ocr.raw, "*Shared Documents*"),
strings.ilike(.scan.ocr.raw, "*expiration*"),
strings.ilike(.scan.ocr.raw, "*office*"),
strings.ilike(.scan.ocr.raw, "*expire*"),
strings.ilike(.scan.ocr.raw, "*expiring*"),
strings.ilike(.scan.ocr.raw, "*kindly*"),
strings.ilike(.scan.ocr.raw, "*renew*"),
strings.ilike(.scan.ocr.raw, "*review"),
strings.ilike(.scan.ocr.raw, "*emails failed*"),
strings.ilike(.scan.ocr.raw, "*kicked out*"),
strings.ilike(.scan.ocr.raw, "*prevented*"),
strings.ilike(.scan.ocr.raw, "*storage quota*"),
strings.ilike(.scan.ocr.raw, "*required now"),
strings.ilike(.scan.ocr.raw, "*cache*"),
strings.ilike(.scan.ocr.raw, "*qr code*"),
strings.ilike(.scan.ocr.raw, "*barcode*"),
strings.ilike(.scan.ocr.raw, "*security update*"),
strings.ilike(.scan.ocr.raw, "*quarantine*")
)
)
)
)
)
// open redirect
and any(body.links,
any(.href_url.rewrite.encoders, strings.icontains(., "open_redirect"))
and not .href_url.domain.root_domain in $org_domains
)
and not (length(headers.references) > 0 or headers.in_reply_to is not null)
and sender.email.domain.root_domain not in $org_domains
and sender.email.domain.root_domain not in (
"bing.com",
"microsoft.com",
"microsoftonline.com",
"microsoftstoreemail.com",
"microsoftsupport.com",
"microsoft365.com",
"office.com",
"onedrive.com",
"sharepointonline.com",
"yammer.com"
)
Detection Logic
Scope: inbound message.
Message contains a Microsoft logo or suspicious terms and use of an open redirect. This has been exploited in the wild to impersonate Microsoft.
- inbound message
any of:
- length(attachments) < 5
- length(body.links) < 10
any of:
any of
attachmentswhere all hold:- .file_type in $file_types_images
- any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft"))
any of
attachmentswhere all hold:- .file_type in $file_types_images
- ( any(file.explode(.), 2 of ( strings.ilike(.scan.ocr.raw, "*password*"), strings.ilike(.scan.ocr.raw, "*unread messages*"), strings.ilike(.scan.ocr.raw, "*Shared Documents*"), strings.ilike(.scan.ocr.raw, "*expiration*"), strings.ilike(.scan.ocr.raw, "*office*"), strings.ilike(.scan.ocr.raw, "*expire*"), strings.ilike(.scan.ocr.raw, "*expiring*"), strings.ilike(.scan.ocr.raw, "*kindly*"), strings.ilike(.scan.ocr.raw, "*renew*"), strings.ilike(.scan.ocr.raw, "*review"), strings.ilike(.scan.ocr.raw, "*emails failed*"), strings.ilike(.scan.ocr.raw, "*kicked out*"), strings.ilike(.scan.ocr.raw, "*prevented*"), strings.ilike(.scan.ocr.raw, "*storage quota*"), strings.ilike(.scan.ocr.raw, "*required now"), strings.ilike(.scan.ocr.raw, "*cache*"), strings.ilike(.scan.ocr.raw, "*qr code*"), strings.ilike(.scan.ocr.raw, "*barcode*"), strings.ilike(.scan.ocr.raw, "*security update*"), strings.ilike(.scan.ocr.raw, "*quarantine*") ) ) )
any of
body.linkswhere all hold:any of
.href_url.rewrite.encoderswhere:- . contains 'open_redirect'
not:
- .href_url.domain.root_domain in $org_domains
none of:
- length(headers.references) > 0
- headers.in_reply_to is set
- sender.email.domain.root_domain not in $org_domains
- sender.email.domain.root_domain not in ('bing.com', 'microsoft.com', 'microsoftonline.com', 'microsoftstoreemail.com', 'microsoftsupport.com', 'microsoft365.com', 'office.com', 'onedrive.com', 'sharepointonline.com', 'yammer.com')
Inspects: attachments[].file_type, body.links, body.links[].href_url.domain.root_domain, body.links[].href_url.rewrite.encoders, headers.in_reply_to, headers.references, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, ml.logo_detect, strings.icontains, strings.ilike, strings.starts_with. Reference lists: $file_types_images, $org_domains.
Indicators Matched (22)
| Field | Match | Value |
|---|---|---|
strings.starts_with | prefix | Microsoft |
strings.ilike | substring | *password* |
strings.ilike | substring | *unread messages* |
strings.ilike | substring | *Shared Documents* |
strings.ilike | substring | *expiration* |
strings.ilike | substring | *office* |
strings.ilike | substring | *expire* |
strings.ilike | substring | *expiring* |
strings.ilike | substring | *kindly* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *review |
strings.ilike | substring | *emails failed* |
10 more
strings.ilike | substring | *kicked out* |
strings.ilike | substring | *prevented* |
strings.ilike | substring | *storage quota* |
strings.ilike | substring | *required now |
strings.ilike | substring | *cache* |
strings.ilike | substring | *qr code* |
strings.ilike | substring | *barcode* |
strings.ilike | substring | *security update* |
strings.ilike | substring | *quarantine* |
strings.icontains | substring | open_redirect |
Stages and Predicates
Stage 1: mql_rule
and
or
any(attachments)
and
attachments.file_type macro "attachments[].file_type in file_types_images"
macro "(\n any(file.explode(.),\n 2 of (\n strings.ilike(.scan.ocr.raw, \"*password*\"),\n strings.ilike(.scan.ocr.raw, \"*unread messages*\"),\n strings.ilike(.scan.ocr.raw, \"*Shared Documents*\"),\n strings.ilike(.scan.ocr.raw, \"*expiration*\"),\n strings.ilike(.scan.ocr.raw, \"*office*\"),\n strings.ilike(.scan.ocr.raw, \"*expire*\"),\n strings.ilike(.scan.ocr.raw, \"*expiring*\"),\n strings.ilike(.scan.ocr.raw, \"*kindly*\"),\n strings.ilike(.scan.ocr.raw, \"*renew*\"),\n strings.ilike(.scan.ocr.raw, \"*review\"),\n strings.ilike(.scan.ocr.raw, \"*emails failed*\"),\n strings.ilike(.scan.ocr.raw, \"*kicked out*\"),\n strings.ilike(.scan.ocr.raw, \"*prevented*\"),\n strings.ilike(.scan.ocr.raw, \"*storage quota*\"),\n strings.ilike(.scan.ocr.raw, \"*required now\"),\n strings.ilike(.scan.ocr.raw, \"*cache*\"),\n strings.ilike(.scan.ocr.raw, \"*qr code*\"),\n strings.ilike(.scan.ocr.raw, \"*barcode*\"),\n strings.ilike(.scan.ocr.raw, \"*security update*\"),\n strings.ilike(.scan.ocr.raw, \"*quarantine*\")\n )\n )\n )"
any(attachments)
and
attachments.file_type macro "attachments[].file_type in file_types_images"
macro "any(ml.logo_detect(.).brands, strings.starts_with(.name, \"Microsoft\"))"
any(body.links)
and
not
body.links.href_url.domain.root_domain macro "body.links[].href_url.domain.root_domain in org_domains"
any(body.links.href_url.rewrite.encoders)
body.links.href_url.rewrite.encoders contains "open_redirect"
not
or
headers.in_reply_to is_not_null
headers.references length_compare "0"
or
attachments length_compare "5"
body.links length_compare "10"
not
sender.email.domain.root_domain in ["bing.com", "microsoft.com", "microsoft365.com", "microsoftonline.com", "microsoftstoreemail.com", "microsoftsupport.com", "office.com", "onedrive.com", "sharepointonline.com", "yammer.com"]
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in org_domains"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.in_reply_to | is_not_null | excludes:headers.in_reply_to | |
headers.references | length_compare | 0 | excludes:headers.references field:"headers.references" value:"0" |
sender.email.domain.root_domain | in | bing.com, microsoft.com, microsoft365.com, microsoftonline.com, microsoftstoreemail.com, microsoftsupport.com, office.com, onedrive.com, sharepointonline.com, yammer.com | excludes:sender.email.domain.root_domain |
Business Email Compromise (BEC) attempt from unsolicited sender
#Detects potential Business Email Compromise (BEC) attacks by analyzing text within the email body from unsolicited senders.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering, Spoofing |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("bec") and .confidence == "high"
)
and
// mismatched From and Reply-to
(
(
length(headers.reply_to) > 0
and all(headers.reply_to,
.email.domain.root_domain != sender.email.domain.root_domain
)
)
or not headers.auth_summary.dmarc.pass
or not headers.auth_summary.spf.pass
)
// negate "via" senders via dmarc authentication or gmail autoforwards
and not (
strings.ilike(headers.return_path.local_part, "*+caf_=*")
and strings.contains(sender.display_name, "via")
and (headers.auth_summary.dmarc.pass)
)
and (
not profile.by_sender().solicited
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
)
Detection Logic
Scope: inbound message.
Detects potential Business Email Compromise (BEC) attacks by analyzing text within the email body from unsolicited senders.
- inbound message
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("bec") and .confidence == "high" )
any of:
all of:
- length(headers.reply_to) > 0
all of
headers.reply_towhere:- .email.domain.root_domain is not sender.email.domain.root_domain
not:
- headers.auth_summary.dmarc.pass
not:
- headers.auth_summary.spf.pass
not:
all of:
- headers.return_path.local_part matches '*+caf_=*'
- sender.display_name contains 'via'
- headers.auth_summary.dmarc.pass
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.reply_to, headers.reply_to[].email.domain.root_domain, headers.return_path.local_part, sender.display_name, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, strings.contains, strings.ilike.
Indicators Matched (2)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | equals | high |
Stages and Predicates
Stage 1: mql_rule
and
or
and
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
profile.by_sender func_call "profile.by_sender().solicited"
not
and
headers.auth_summary.dmarc.pass eq "true"
headers.return_path.local_part match "+caf_="
sender.display_name contains "via"
or
not
headers.auth_summary.dmarc.pass eq "true"
not
headers.auth_summary.spf.pass eq "true"
and
headers.reply_to length_compare "0"
macro "all(headers.reply_to,\n .email.domain.root_domain != sender.email.domain.root_domain\n )"
type.inbound eq "true"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"bec\") and .confidence == \"high\"\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
headers.return_path.local_part | match | +caf_= | excludes:headers.return_path.local_part field:"headers.return_path.local_part" value:"+caf_=" |
sender.display_name | contains | via | excludes:sender.display_name field:"sender.display_name" value:"via" |
Business Email Compromise (BEC) attempt from untrusted sender
#Detects potential Business Email Compromise (BEC) attacks by analyzing text within the email body from first-time senders.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("bec") and .confidence == "high"
)
// negating legit replies
and not (
(
(
subject.is_reply
or subject.is_forward
// out of office auto-reply
// the NLU model will handle these better natively soon
or strings.istarts_with(subject.subject, "Automatic reply:")
)
and (length(headers.references) > 0 or headers.in_reply_to is not null)
)
or (
// calendar invite responses
regex.icontains(subject.base,
'(?:Accepted|Declined|New Time Proposed|Tentative):'
)
and any(attachments, .content_type == "text/calendar")
and profile.by_sender_email().solicited
)
)
and (
not profile.by_sender().solicited
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
Detection Logic
Scope: inbound message.
Detects potential Business Email Compromise (BEC) attacks by analyzing text within the email body from first-time senders.
- inbound message
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("bec") and .confidence == "high" )
none of:
all of:
any of:
- subject.is_reply
- subject.is_forward
- subject.subject starts with 'Automatic reply:'
any of:
- length(headers.references) > 0
- headers.in_reply_to is set
all of:
- subject.base matches '(?:Accepted|Declined|New Time Proposed|Tentative):'
any of
attachmentswhere:- .content_type is 'text/calendar'
- profile.by_sender_email().solicited
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
Inspects: attachments[].content_type, body.current_thread.text, headers.auth_summary.dmarc.pass, headers.in_reply_to, headers.references, sender.email.domain.root_domain, subject.base, subject.is_forward, subject.is_reply, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, profile.by_sender_email, regex.icontains, strings.istarts_with. Reference lists: $high_trust_sender_root_domains.
Indicators Matched (2)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | equals | high |
Stages and Predicates
Stage 1: mql_rule
and
not
or
and
any(attachments)
attachments.content_type eq "text/calendar"
profile.by_sender_email func_call "profile.by_sender_email().solicited"
subject.base regex_match "(?:Accepted|Declined|New Time Proposed|Tentative):"
and
or
headers.in_reply_to is_not_null
headers.references length_compare "0"
or
subject.is_forward eq "true"
subject.is_reply eq "true"
subject.subject starts_with "Automatic reply:"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
and
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
profile.by_sender func_call "profile.by_sender().solicited"
type.inbound eq "true"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"bec\") and .confidence == \"high\"\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
attachments | array_any | excludes:attachments | |
subject.base | regex_match | (?:Accepted|Declined|New Time Proposed|Tentative): | excludes:subject.base field:"subject.base" value:"(?:Accepted|Declined|New Time Proposed|Tentative):" |
headers.in_reply_to | is_not_null | excludes:headers.in_reply_to | |
headers.references | length_compare | 0 | excludes:headers.references field:"headers.references" value:"0" |
subject.is_forward | eq | true | excludes:subject.is_forward field:"subject.is_forward" value:"true" |
subject.is_reply | eq | true | excludes:subject.is_reply field:"subject.is_reply" value:"true" |
subject.subject | starts_with | Automatic reply: | excludes:subject.subject field:"subject.subject" value:"Automatic reply:" |
Business Email Compromise (BEC) with request for mobile number
#This rule detects unsolicited messages with a small plain text body, that is attempting to solicit a mobile number.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
length(body.current_thread.text) < 500
or any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
.name == "disclaimer"
),
.text
),
(length(body.current_thread.text) - length(.)) < 500
)
)
and length(filter(attachments, .file_type not in $file_types_images)) == 0
and regex.icontains(body.current_thread.text,
'(?:mobile|contact|current|reliable|latest).{0,10}(?:phone|number|#|\bno)|whatsapp|\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\bnum\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\b|stay connected|hit you up)|forward.{0,25}(?:\bnum\b|#)|get (?:your.{0,25}(?:number|\bnum\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred|personal).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\bnum\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\bnum\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\bnum\b|#|line)|(?:share|send|provide).{0,25}preferred.{0,25}(?:contact|communication).{0,15}(?:method|info|means|way)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number|(?:share|send|provide).{0,25}way.{0,25}(?:reach|contact).{0,25}(?:call|text|sms|whatsapp)|(?:reply|respond).{0,20}with.{0,15}(?:your\s)?(?:phone|cell|mobile).{0,5}(?:number|\bnum\b|#)'
)
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("bec", "advance_fee") and .confidence != "low"
)
or (
// confidence can be low on very short bodies
length(body.current_thread.text) < 550
and (
any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec")
or any(ml.nlu_classifier(sender.display_name).intents, .name == "bec")
or any(ml.nlu_classifier(body.current_thread.text).entities,
strings.icontains(.text, "kindly")
)
)
)
)
and (
(
(length(headers.references) > 0 or headers.in_reply_to is null)
and not (
(
strings.istarts_with(subject.subject, "RE:")
or strings.istarts_with(subject.subject, "RES:")
or strings.istarts_with(subject.subject, "R:")
or strings.istarts_with(subject.subject, "ODG:")
or strings.istarts_with(subject.subject, "答复:")
or strings.istarts_with(subject.subject, "AW:")
or strings.istarts_with(subject.subject, "TR:")
or strings.istarts_with(subject.subject, "FWD:")
or regex.imatch(subject.subject,
'(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*'
)
)
)
)
or length(headers.references) == 0
)
and (
not profile.by_sender().solicited
or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign
Detection Logic
Scope: inbound message.
This rule detects unsolicited messages with a small plain text body, that is attempting to solicit a mobile number.
- inbound message
any of:
- length(body.current_thread.text) < 500
- any(map(filter(ml.nlu_classifier(body.current_thread.text).entities, .name == "disclaimer" ), .text ), (length(body.current_thread.text) - length(.)) < 500 )
- length(filter(attachments, .file_type not in $file_types_images)) == 0
- body.current_thread.text matches '(?:mobile|contact|current|reliable|latest).{0,10}(?:phone|number|#|\\bno)|whatsapp|\\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\\bnum\\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\\b|stay connected|hit you up)|forward.{0,25}(?:\\bnum\\b|#)|get (?:your.{0,25}(?:number|\\bnum\\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred|personal).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\\bnum\\b|#|line)|(?:share|send|provide).{0,25}preferred.{0,25}(?:contact|communication).{0,15}(?:method|info|means|way)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number|(?:share|send|provide).{0,25}way.{0,25}(?:reach|contact).{0,25}(?:call|text|sms|whatsapp)|(?:reply|respond).{0,20}with.{0,15}(?:your\\s)?(?:phone|cell|mobile).{0,5}(?:number|\\bnum\\b|#)'
any of:
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("bec", "advance_fee") and .confidence != "low" )
all of:
- length(body.current_thread.text) < 550
any of:
- any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec")
- any(ml.nlu_classifier(sender.display_name).intents, .name == "bec")
- any(ml.nlu_classifier(body.current_thread.text).entities, strings.icontains(.text, "kindly") )
any of:
all of:
any of:
- length(headers.references) > 0
- headers.in_reply_to is missing
none of:
- subject.subject starts with 'RE:'
- subject.subject starts with 'RES:'
- subject.subject starts with 'R:'
- subject.subject starts with 'ODG:'
- subject.subject starts with '答复:'
- subject.subject starts with 'AW:'
- subject.subject starts with 'TR:'
- subject.subject starts with 'FWD:'
- subject.subject matches '(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*'
- length(headers.references) == 0
any of:
not:
- profile.by_sender().solicited
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
Inspects: attachments[].file_type, body.current_thread.text, headers.in_reply_to, headers.references, sender.display_name, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, regex.imatch, strings.icontains, strings.istarts_with. Reference lists: $file_types_images.
Indicators Matched (7)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | disclaimer |
regex.icontains | regex | (?:mobile|contact|current|reliable|latest).{0,10}(?:phone|number|#|\bno)|whatsapp|\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\bnum\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\b|stay connected|hit you up)|forward.{0,25}(?:\bnum\b|#)|get (?:your.{0,25}(?:number|\bnum\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred|personal).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\bnum\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\bnum\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\bnum\b|#|line)|(?:share|send|provide).{0,25}preferred.{0,25}(?:contact|communication).{0,15}(?:method|info|means|way)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number|(?:share|send|provide).{0,25}way.{0,25}(?:reach|contact).{0,25}(?:call|text|sms|whatsapp)|(?:reply|respond).{0,20}with.{0,15}(?:your\s)?(?:phone|cell|mobile).{0,5}(?:number|\bnum\b|#) |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | advance_fee |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | bec |
ml.nlu_classifier(sender.display_name).intents[].name | equals | bec |
strings.icontains | substring | kindly |
Stages and Predicates
Stage 1: mql_rule
and
or
and
not
or
subject.subject regex_match "(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*"
subject.subject starts_with "AW:"
subject.subject starts_with "FWD:"
subject.subject starts_with "ODG:"
subject.subject starts_with "R:"
subject.subject starts_with "RE:"
subject.subject starts_with "RES:"
subject.subject starts_with "TR:"
subject.subject starts_with "答复:"
or
headers.in_reply_to is_null
headers.references length_compare "0"
headers.references length_compare "0"
or
and
or
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n strings.icontains(.text, \"kindly\")\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).intents, .name == \"bec\")"
macro "any(ml.nlu_classifier(sender.display_name).intents, .name == \"bec\")"
body.current_thread.text length_compare "550"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"bec\", \"advance_fee\") and .confidence != \"low\"\n )"
or
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
or
body.current_thread.text length_compare "500"
macro "any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"disclaimer\"\n ),\n .text\n ),\n (length(body.current_thread.text) - length(.)) < 500\n )"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
body.current_thread.text regex_match "(?:mobile|contact|current|reliable|latest).{0,10}(?:phone|number|#|\\bno)|whatsapp|\\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\\bnum\\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\\b|stay connected|hit you up)|forward.{0,25}(?:\\bnum\\b|#)|get (?:your.{0,25}(?:number|\\bnum\\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred|personal).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\\bnum\\b|#|line)|(?:share|send|provide).{0,25}preferred.{0,25}(?:contact|communication).{0,15}(?:method|info|means|way)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number|(?:share|send|provide).{0,25}way.{0,25}(?:reach|contact).{0,25}(?:call|text|sms|whatsapp)|(?:reply|respond).{0,20}with.{0,15}(?:your\\s)?(?:phone|cell|mobile).{0,5}(?:number|\\bnum\\b|#)"
length func_call "length(filter(attachments, .file_type not in $file_types_images)) == 0"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
headers.in_reply_to | is_null | field:"headers.in_reply_to" kind:is_null | |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Business Email Compromise: Request for mobile number via reply thread hijacking
#This rule detects BEC attacks that use reply threads to solicit mobile numbers, evading detection rules that exclude RE: subjects.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and 0 < length(body.previous_threads) < 3
and length(filter(attachments, .file_type not in $file_types_images)) == 0
// Check previous_threads for mobile solicitation patterns
and any(body.previous_threads,
(
length(.text) < 500
// ignore disclaimers in body length calculation
or (
any(map(filter(ml.nlu_classifier(.text).entities,
.name == "disclaimer"
),
.text
),
(length(..text) - length(.)) < 500
)
)
)
and regex.icontains(.text,
'(?:mobile|suitable|contact|current|cell|call|another).{0,10}(?:phone|number|#|\bno)|personal\s?(?:phone|cell|number|#)|whatsapp|\bcell|personalcell|(?:reliable|recent).{0,30}(?:phone|number).{0,15}contact|(?:share|send|confirm).{0,20}number.{0,25}(?:text|sms|whatsapp|contact|reach\syou[\s,.\?](?:by|whether|when|for))|best\s+(?:number|#).{0,10}(?:text|sms|contact|call|message|in[-\s]?touch|to\suse)|best\s+way.{0,25}(?:reach|contact).{0,25}(?:text|sms|whatsapp|call|message)'
)
)
// NLU analysis on previous_threads content
and (
any(body.previous_threads,
any(ml.nlu_classifier(.text).intents,
.name in ("bec", "advance_fee") and .confidence in ("medium", "high")
)
)
or (
// confidence can be low on very short bodies
any(body.previous_threads, length(.text) < 550)
and (
any(body.previous_threads,
any(ml.nlu_classifier(.text).intents, .name == "bec")
)
or any(ml.nlu_classifier(sender.display_name).intents, .name == "bec")
or any(body.previous_threads,
any(ml.nlu_classifier(.text).entities,
strings.icontains(.text, "kindly")
)
)
)
)
)
// Sender analysis
and (
not profile.by_sender().solicited
or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign
// not high trust sender domains
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
// Ensure this is likely a hijacked thread (sender doesn't match thread participants)
and (length(headers.references) > 0 or headers.in_reply_to is not null)
Detection Logic
Scope: inbound message.
This rule detects BEC attacks that use reply threads to solicit mobile numbers, evading detection rules that exclude RE: subjects.
- inbound message
all of:
- (0) < (length(body.previous_threads))
- (length(body.previous_threads)) < (3)
- length(filter(attachments, .file_type not in $file_types_images)) == 0
any of
body.previous_threadswhere all hold:any of:
- length(.text) < 500
- ( any(map(filter(ml.nlu_classifier(.text).entities, .name == "disclaimer" ), .text ), (length(..text) - length(.)) < 500 ) )
- .text matches '(?:mobile|suitable|contact|current|cell|call|another).{0,10}(?:phone|number|#|\\bno)|personal\\s?(?:phone|cell|number|#)|whatsapp|\\bcell|personalcell|(?:reliable|recent).{0,30}(?:phone|number).{0,15}contact|(?:share|send|confirm).{0,20}number.{0,25}(?:text|sms|whatsapp|contact|reach\\syou[\\s,.\\?](?:by|whether|when|for))|best\\s+(?:number|#).{0,10}(?:text|sms|contact|call|message|in[-\\s]?touch|to\\suse)|best\\s+way.{0,25}(?:reach|contact).{0,25}(?:text|sms|whatsapp|call|message)'
any of:
any of
body.previous_threadswhere:- any(ml.nlu_classifier(.text).intents, .name in ("bec", "advance_fee") and .confidence in ("medium", "high") )
all of:
any of
body.previous_threadswhere:- length(.text) < 550
any of:
any of
body.previous_threadswhere:- any(ml.nlu_classifier(.text).intents, .name == "bec")
- any(ml.nlu_classifier(sender.display_name).intents, .name == "bec")
any of
body.previous_threadswhere:- any(ml.nlu_classifier(.text).entities, strings.icontains(.text, "kindly") )
any of:
not:
- profile.by_sender().solicited
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
any of:
- length(headers.references) > 0
- headers.in_reply_to is set
Inspects: attachments[].file_type, body.previous_threads, body.previous_threads[].text, headers.auth_summary.dmarc.pass, headers.in_reply_to, headers.references, sender.display_name, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, strings.icontains. Reference lists: $file_types_images, $high_trust_sender_root_domains.
Indicators Matched (9)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.previous_threads[].text).entities[].name | equals | disclaimer |
regex.icontains | regex | (?:mobile|suitable|contact|current|cell|call|another).{0,10}(?:phone|number|#|\bno)|personal\s?(?:phone|cell|number|#)|whatsapp|\bcell|personalcell|(?:reliable|recent).{0,30}(?:phone|number).{0,15}contact|(?:share|send|confirm).{0,20}number.{0,25}(?:text|sms|whatsapp|contact|reach\syou[\s,.\?](?:by|whether|when|for))|best\s+(?:number|#).{0,10}(?:text|sms|contact|call|message|in[-\s]?touch|to\suse)|best\s+way.{0,25}(?:reach|contact).{0,25}(?:text|sms|whatsapp|call|message) |
ml.nlu_classifier(body.previous_threads[].text).intents[].name | member | bec |
ml.nlu_classifier(body.previous_threads[].text).intents[].name | member | advance_fee |
ml.nlu_classifier(body.previous_threads[].text).intents[].confidence | member | medium |
ml.nlu_classifier(body.previous_threads[].text).intents[].confidence | member | high |
ml.nlu_classifier(body.previous_threads[].text).intents[].name | equals | bec |
ml.nlu_classifier(sender.display_name).intents[].name | equals | bec |
strings.icontains | substring | kindly |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
any(body.previous_threads)
macro "any(ml.nlu_classifier(.text).entities,\n strings.icontains(.text, \"kindly\")\n )"
any(body.previous_threads)
macro "any(ml.nlu_classifier(.text).intents, .name == \"bec\")"
macro "any(ml.nlu_classifier(sender.display_name).intents, .name == \"bec\")"
any(body.previous_threads)
body.previous_threads.text length_compare "550"
any(body.previous_threads)
macro "any(ml.nlu_classifier(.text).intents,\n .name in (\"bec\", \"advance_fee\") and .confidence in (\"medium\", \"high\")\n )"
any(body.previous_threads)
and
or
body.previous_threads.text length_compare "500"
macro "(\n any(map(filter(ml.nlu_classifier(.text).entities,\n .name == \"disclaimer\"\n ),\n .text\n ),\n (length(..text) - length(.)) < 500\n )\n )"
body.previous_threads.text regex_match "(?:mobile|suitable|contact|current|cell|call|another).{0,10}(?:phone|number|#|\\bno)|personal\\s?(?:phone|cell|number|#)|whatsapp|\\bcell|personalcell|(?:reliable|recent).{0,30}(?:phone|number).{0,15}contact|(?:share|send|confirm).{0,20}number.{0,25}(?:text|sms|whatsapp|contact|reach\\syou[\\s,.\\?](?:by|whether|when|for))|best\\s+(?:number|#).{0,10}(?:text|sms|contact|call|message|in[-\\s]?touch|to\\suse)|best\\s+way.{0,25}(?:reach|contact).{0,25}(?:text|sms|whatsapp|call|message)"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
or
headers.in_reply_to is_not_null
headers.references length_compare "0"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
body.previous_threads length_compare "0"
body.previous_threads length_compare "3"
length func_call "length(filter(attachments, .file_type not in $file_types_images)) == 0"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
headers.in_reply_to | is_not_null | field:"headers.in_reply_to" kind:is_not_null | |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing solicitation in message body
#A fraudulent invoice/receipt found in the body of the message. Callback phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Free email provider, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and length(attachments) == 0
and (
not profile.by_sender().solicited
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
)
and (
sender.email.domain.root_domain in $free_email_providers
or sender.email.domain.tld in $suspicious_tlds
or network.whois(sender.email.domain).found == false
or headers.mailer in~ ("Microsoft CDO for Windows 2000")
or (
length(recipients.to) == 1
and all(recipients.to, .email.domain.domain not in $org_domains)
)
)
and (
// this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
regex.icontains(body.current_thread.text,
'(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
)
or any(ml.logo_detect(file.message_screenshot()).brands,
.name in ("PayPal", "Norton", "GeekSquad", "Ebay", "McAfee", "AT&T")
)
//
// This rule makes use of a beta feature and is subject to change without notice
// using the beta feature in custom rules is not suggested until it has been formally released
//
or regex.icontains(beta.ocr(file.message_screenshot()).text,
'(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
)
)
and length(body.current_thread.text) < 1750
and (
(
// this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
// however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
// caused by messages which mention cancelling or otherwise managing a subscription
// it is also synced and below for message_screenshot OCR output
3 of (
strings.icontains(body.current_thread.text, 'purchase'),
strings.icontains(body.current_thread.text, 'payment'),
strings.icontains(body.current_thread.text, 'transaction'),
strings.icontains(body.current_thread.text, 'subscription'),
strings.icontains(body.current_thread.text, 'antivirus'),
strings.icontains(body.current_thread.text, 'order'),
strings.icontains(body.current_thread.text, 'support'),
strings.icontains(body.current_thread.text, 'help line'),
strings.icontains(body.current_thread.text, 'receipt'),
strings.icontains(body.current_thread.text, 'invoice'),
strings.icontains(body.current_thread.text, 'call'),
strings.icontains(body.current_thread.text, 'cancel'),
strings.icontains(body.current_thread.text, 'renew'),
strings.icontains(body.current_thread.text, 'refund'),
regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
strings.icontains(body.current_thread.text, "+1"),
strings.icontains(body.current_thread.text, "amount"),
strings.icontains(body.current_thread.text, "charged"),
strings.icontains(body.current_thread.text, "crypto"),
strings.icontains(body.current_thread.text, "wallet address"),
regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
)
// phone number regex
and regex.icontains(body.current_thread.text,
'\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
'\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
)
)
or (
any(file.explode(file.message_screenshot()),
// this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
// and above for current_thread.text
3 of (
strings.icontains(.scan.ocr.raw, 'purchase'),
strings.icontains(.scan.ocr.raw, 'payment'),
strings.icontains(.scan.ocr.raw, 'transaction'),
strings.icontains(.scan.ocr.raw, 'subscription'),
strings.icontains(.scan.ocr.raw, 'antivirus'),
strings.icontains(.scan.ocr.raw, 'order'),
strings.icontains(.scan.ocr.raw, 'support'),
strings.icontains(.scan.ocr.raw, 'help line'),
strings.icontains(.scan.ocr.raw, 'receipt'),
strings.icontains(.scan.ocr.raw, 'invoice'),
strings.icontains(.scan.ocr.raw, 'call'),
strings.icontains(.scan.ocr.raw, 'helpdesk'),
strings.icontains(.scan.ocr.raw, 'cancel'),
strings.icontains(.scan.ocr.raw, 'renew'),
strings.icontains(.scan.ocr.raw, 'refund'),
regex.icontains(.scan.ocr.raw, "(?:reach|contact) us at"),
strings.icontains(.scan.ocr.raw, '+1'),
strings.icontains(.scan.ocr.raw, 'amount'),
strings.icontains(.scan.ocr.raw, 'charged'),
strings.icontains(.scan.ocr.raw, 'crypto'),
strings.icontains(.scan.ocr.raw, 'wallet address'),
regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
)
// phone number regex
and regex.icontains(.scan.ocr.raw,
'\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
'\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
)
// negate messages with previous threads. While callback phishing with thread hijacking or with current_thread
// padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
and not regex.icount(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3
// this notation of previous threads often only occurs once
and not regex.icontains(.scan.ocr.raw, 'wrote:[\r\n]')
)
)
)
// not high trust sender domains
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
and not strings.ends_with(headers.message_id, "@shopify.com>")
Detection Logic
Scope: inbound message.
A fraudulent invoice/receipt found in the body of the message. Callback phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment.
- inbound message
- length(attachments) == 0
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of:
- sender.email.domain.root_domain in $free_email_providers
- sender.email.domain.tld in $suspicious_tlds
- network.whois(sender.email.domain).found == false
- headers.mailer in ('Microsoft CDO for Windows 2000')
all of:
- length(recipients.to) == 1
all of
recipients.towhere:- .email.domain.domain not in $org_domains
any of:
- body.current_thread.text matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
- any(ml.logo_detect(file.message_screenshot()).brands, .name in ("PayPal", "Norton", "GeekSquad", "Ebay", "McAfee", "AT&T") )
- regex.icontains(beta.ocr(file.message_screenshot()).text, '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)' )
- length(body.current_thread.text) < 1750
any of:
all of:
at least 3 of:
- body.current_thread.text contains 'purchase'
- body.current_thread.text contains 'payment'
- body.current_thread.text contains 'transaction'
- body.current_thread.text contains 'subscription'
- body.current_thread.text contains 'antivirus'
- body.current_thread.text contains 'order'
- body.current_thread.text contains 'support'
- body.current_thread.text contains 'help line'
- body.current_thread.text contains 'receipt'
- body.current_thread.text contains 'invoice'
- body.current_thread.text contains 'call'
- body.current_thread.text contains 'cancel'
- body.current_thread.text contains 'renew'
- body.current_thread.text contains 'refund'
- body.current_thread.text matches '(?:reach|contact) us at'
- body.current_thread.text contains '+1'
- body.current_thread.text contains 'amount'
- body.current_thread.text contains 'charged'
- body.current_thread.text contains 'crypto'
- body.current_thread.text contains 'wallet address'
- body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
body.current_thread.text matches any of 2 patterns
\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
- ( any(file.explode(file.message_screenshot()), // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml // and above for current_thread.text 3 of ( strings.icontains(.scan.ocr.raw, 'purchase'), strings.icontains(.scan.ocr.raw, 'payment'), strings.icontains(.scan.ocr.raw, 'transaction'), strings.icontains(.scan.ocr.raw, 'subscription'), strings.icontains(.scan.ocr.raw, 'antivirus'), strings.icontains(.scan.ocr.raw, 'order'), strings.icontains(.scan.ocr.raw, 'support'), strings.icontains(.scan.ocr.raw, 'help line'), strings.icontains(.scan.ocr.raw, 'receipt'), strings.icontains(.scan.ocr.raw, 'invoice'), strings.icontains(.scan.ocr.raw, 'call'), strings.icontains(.scan.ocr.raw, 'helpdesk'), strings.icontains(.scan.ocr.raw, 'cancel'), strings.icontains(.scan.ocr.raw, 'renew'), strings.icontains(.scan.ocr.raw, 'refund'), regex.icontains(.scan.ocr.raw, "(?:reach|contact) us at"), strings.icontains(.scan.ocr.raw, '+1'), strings.icontains(.scan.ocr.raw, 'amount'), strings.icontains(.scan.ocr.raw, 'charged'), strings.icontains(.scan.ocr.raw, 'crypto'), strings.icontains(.scan.ocr.raw, 'wallet address'), regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'), ) // phone number regex and regex.icontains(.scan.ocr.raw, '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}', '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}' ) // negate messages with previous threads. While callback phishing with thread hijacking or with current_thread // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks and not regex.icount(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3 // this notation of previous threads often only occurs once and not regex.icontains(.scan.ocr.raw, 'wrote:[\r\n]') ) )
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
not:
- headers.message_id ends with '@shopify.com>'
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.mailer, headers.message_id, recipients.to, recipients.to[].email.domain.domain, sender.email.domain, sender.email.domain.root_domain, sender.email.domain.tld, type.inbound. Sensors: beta.ocr, file.explode, file.message_screenshot, ml.logo_detect, network.whois, profile.by_sender, regex.icontains, regex.icount, strings.ends_with, strings.icontains. Reference lists: $free_email_providers, $high_trust_sender_root_domains, $org_domains, $suspicious_tlds.
Indicators Matched (32)
| Field | Match | Value |
|---|---|---|
headers.mailer | member | Microsoft CDO for Windows 2000 |
regex.icontains | regex | (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t) |
ml.logo_detect(file.message_screenshot()).brands[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
strings.icontains | substring | subscription |
20 more
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
macro "3 of (\n strings.icontains(body.current_thread.text, 'purchase'),\n strings.icontains(body.current_thread.text, 'payment'),\n strings.icontains(body.current_thread.text, 'transaction'),\n strings.icontains(body.current_thread.text, 'subscription'),\n strings.icontains(body.current_thread.text, 'antivirus'),\n strings.icontains(body.current_thread.text, 'order'),\n strings.icontains(body.current_thread.text, 'support'),\n strings.icontains(body.current_thread.text, 'help line'),\n strings.icontains(body.current_thread.text, 'receipt'),\n strings.icontains(body.current_thread.text, 'invoice'),\n strings.icontains(body.current_thread.text, 'call'),\n strings.icontains(body.current_thread.text, 'cancel'),\n strings.icontains(body.current_thread.text, 'renew'),\n strings.icontains(body.current_thread.text, 'refund'),\n regex.icontains(body.current_thread.text, \"(?:reach|contact) us at\"),\n strings.icontains(body.current_thread.text, \"+1\"),\n strings.icontains(body.current_thread.text, \"amount\"),\n strings.icontains(body.current_thread.text, \"charged\"),\n strings.icontains(body.current_thread.text, \"crypto\"),\n strings.icontains(body.current_thread.text, \"wallet address\"),\n regex.icontains(body.current_thread.text, '\\$\\d{3}\\.\\d{2}\\b'),\n )"
macro "(\n any(file.explode(file.message_screenshot()),\n // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml\n // and above for current_thread.text\n 3 of (\n strings.icontains(.scan.ocr.raw, 'purchase'),\n strings.icontains(.scan.ocr.raw, 'payment'),\n strings.icontains(.scan.ocr.raw, 'transaction'),\n strings.icontains(.scan.ocr.raw, 'subscription'),\n strings.icontains(.scan.ocr.raw, 'antivirus'),\n strings.icontains(.scan.ocr.raw, 'order'),\n strings.icontains(.scan.ocr.raw, 'support'),\n strings.icontains(.scan.ocr.raw, 'help line'),\n strings.icontains(.scan.ocr.raw, 'receipt'),\n strings.icontains(.scan.ocr.raw, 'invoice'),\n strings.icontains(.scan.ocr.raw, 'call'),\n strings.icontains(.scan.ocr.raw, 'helpdesk'),\n strings.icontains(.scan.ocr.raw, 'cancel'),\n strings.icontains(.scan.ocr.raw, 'renew'),\n strings.icontains(.scan.ocr.raw, 'refund'),\n regex.icontains(.scan.ocr.raw, \"(?:reach|contact) us at\"),\n strings.icontains(.scan.ocr.raw, '+1'),\n strings.icontains(.scan.ocr.raw, 'amount'),\n strings.icontains(.scan.ocr.raw, 'charged'),\n strings.icontains(.scan.ocr.raw, 'crypto'),\n strings.icontains(.scan.ocr.raw, 'wallet address'),\n regex.icontains(.scan.ocr.raw, '\\$\\d{3}\\.\\d{2}\\b'),\n )\n // phone number regex\n and regex.icontains(.scan.ocr.raw,\n '\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}',\n '\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}'\n )\n\n // negate messages with previous threads. While callback phishing with thread hijacking or with current_thread \n // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks\n and not regex.icount(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3\n // this notation of previous threads often only occurs once\n and not regex.icontains(.scan.ocr.raw, 'wrote:[\\r\\n]')\n )\n )"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
and
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
profile.by_sender func_call "profile.by_sender().solicited"
or
and
recipients.to length_compare "1"
macro "all(recipients.to, .email.domain.domain not in $org_domains)"
headers.mailer eq "Microsoft CDO for Windows 2000"
network.whois func_call "network.whois(sender.email.domain).found == false"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in free_email_providers"
sender.email.domain.tld macro "sender.email.domain.tld in suspicious_tlds"
or
body.current_thread.text regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
regex.icontains func_call "regex.icontains(beta.ocr(file.message_screenshot()).text,\n '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'\n )"
macro "any(ml.logo_detect(file.message_screenshot()).brands,\n .name in (\"PayPal\", \"Norton\", \"GeekSquad\", \"Ebay\", \"McAfee\", \"AT&T\")\n )"
not
headers.message_id ends_with "@shopify.com>"
attachments length_compare "0"
body.current_thread.text length_compare "1750"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
headers.mailer | in |
| field:"headers.mailer" kind:in value:"Microsoft CDO for Windows 2000" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.message_id | ends_with | @shopify.com> | excludes:headers.message_id field:"headers.message_id" value:"@shopify.com>" |
COVID-19 themed fraud with sender and reply-to mismatch or compensation award
#Detects potential COVID-19 themed BEC/Fraud scams by analyzing text within the email body for mentions of COVID-19 assistance, compensation, or awards from mismatched senders and other suspicious language.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Free email provider, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// mismatched sender (From) and Reply-to + freemail
and (
length(headers.reply_to) > 0
and all(headers.reply_to,
.email.domain.root_domain != sender.email.domain.root_domain
and .email.domain.root_domain in $free_email_providers
)
)
// use of honorific
and regex.icontains(body.current_thread.text,
'(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\.?[ \t]+',
'Dear Sir'
)
// mention of covid or an international organization
and regex.icontains(body.current_thread.text,
'international (court of justice|monetary fund)',
'united nations',
'western union',
'world bank',
'world health organization',
'interpol',
'treasury',
'\bFEMA\b',
'\bIMF\b'
)
// and mention of covid in subject or body
and (
regex.icontains(subject.subject, 'covid(.{0,5}19)?\b')
or regex.icontains(body.current_thread.text, 'covid(.{0,5}19)?\b')
)
// Check for compensation or award related language
and (
2 of (
any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "urgency"
),
any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "request"
),
any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "financial"
)
)
or regex.icontains(subject.subject,
'compensation.{0,20}(award|fund)',
'covid.{0,20}(compensation|award)',
'selected.{0,30}(compensation|award)',
'claim your award',
'reference no'
)
or regex.icontains(body.current_thread.text,
'compensation.{0,20}(award|fund)',
'covid.{0,20}(compensation|award)',
'selected.{0,30}(compensation|award)',
'claim your award',
'reference no\W\s*[^\s]*cov(?:id)?(?:.{0,5}19)?\b'
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
Detection Logic
Scope: inbound message.
Detects potential COVID-19 themed BEC/Fraud scams by analyzing text within the email body for mentions of COVID-19 assistance, compensation, or awards from mismatched senders and other suspicious language.
- inbound message
all of:
- length(headers.reply_to) > 0
all of
headers.reply_towhere all hold:- .email.domain.root_domain is not sender.email.domain.root_domain
- .email.domain.root_domain in $free_email_providers
body.current_thread.text matches any of 2 patterns
(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\.?[ \t]+Dear Sir
body.current_thread.text matches any of 9 patterns
international (court of justice|monetary fund)united nationswestern unionworld bankworld health organizationinterpoltreasury\bFEMA\b\bIMF\b
any of:
- subject.subject matches 'covid(.{0,5}19)?\\b'
- body.current_thread.text matches 'covid(.{0,5}19)?\\b'
any of:
at least 2 of:
- any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency" )
- any(ml.nlu_classifier(body.current_thread.text).entities, .name == "request" )
- any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial" )
subject.subject matches any of 5 patterns
compensation.{0,20}(award|fund)covid.{0,20}(compensation|award)selected.{0,30}(compensation|award)claim your awardreference no
body.current_thread.text matches any of 5 patterns
compensation.{0,20}(award|fund)covid.{0,20}(compensation|award)selected.{0,30}(compensation|award)claim your awardreference no\W\s*[^\s]*cov(?:id)?(?:.{0,5}19)?\b
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.reply_to, headers.reply_to[].email.domain.root_domain, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.icontains. Reference lists: $free_email_providers, $high_trust_sender_root_domains.
Indicators Matched (21)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | (?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\.?[ \t]+ |
regex.icontains | regex | Dear Sir |
regex.icontains | regex | international (court of justice|monetary fund) |
regex.icontains | regex | united nations |
regex.icontains | regex | western union |
regex.icontains | regex | world bank |
regex.icontains | regex | world health organization |
regex.icontains | regex | interpol |
regex.icontains | regex | treasury |
regex.icontains | regex | \bFEMA\b |
regex.icontains | regex | \bIMF\b |
regex.icontains | regex | covid(.{0,5}19)?\b |
9 more
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | urgency |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | request |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | financial |
regex.icontains | regex | compensation.{0,20}(award|fund) |
regex.icontains | regex | covid.{0,20}(compensation|award) |
regex.icontains | regex | selected.{0,30}(compensation|award) |
regex.icontains | regex | claim your award |
regex.icontains | regex | reference no |
regex.icontains | regex | reference no\W\s*[^\s]*cov(?:id)?(?:.{0,5}19)?\b |
Stages and Predicates
Stage 1: mql_rule
and
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
and
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"financial\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"request\"\n )"
and
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"financial\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"urgency\"\n )"
and
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"request\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"urgency\"\n )"
body.current_thread.text regex_match "claim your award"
body.current_thread.text regex_match "compensation.{0,20}(award|fund)"
body.current_thread.text regex_match "covid.{0,20}(compensation|award)"
body.current_thread.text regex_match "reference no\\W\\s*[^\\s]*cov(?:id)?(?:.{0,5}19)?\\b"
body.current_thread.text regex_match "selected.{0,30}(compensation|award)"
subject.subject regex_match "claim your award"
subject.subject regex_match "compensation.{0,20}(award|fund)"
subject.subject regex_match "covid.{0,20}(compensation|award)"
subject.subject regex_match "reference no"
subject.subject regex_match "selected.{0,30}(compensation|award)"
or
body.current_thread.text regex_match "(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\\.?[ \\t]+"
body.current_thread.text regex_match "Dear Sir"
or
body.current_thread.text regex_match "\\bFEMA\\b"
body.current_thread.text regex_match "\\bIMF\\b"
body.current_thread.text regex_match "international (court of justice|monetary fund)"
body.current_thread.text regex_match "interpol"
body.current_thread.text regex_match "treasury"
body.current_thread.text regex_match "united nations"
body.current_thread.text regex_match "western union"
body.current_thread.text regex_match "world bank"
body.current_thread.text regex_match "world health organization"
or
body.current_thread.text regex_match "covid(.{0,5}19)?\\b"
subject.subject regex_match "covid(.{0,5}19)?\\b"
headers.reply_to length_compare "0"
type.inbound eq "true"
macro "all(headers.reply_to,\n .email.domain.root_domain != sender.email.domain.root_domain\n and .email.domain.root_domain in $free_email_providers\n )"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
subject.subject | regex_match |
| field:"subject.subject" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Credential theft with 'safe content' deception and social engineering topics
#Detects messages containing credential theft language combined with social engineering topics like secure messages, notifications, or authentication alerts. The rule specifically identifies emails that deceptively claim to be from a 'safe sender' or contain 'safe content' in the first line, which is a common tactic used to bypass security filters and gain user trust.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Social engineering, Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "cred_theft" and .confidence != "low"
)
and (
any(ml.nlu_classifier(body.current_thread.text).topics,
.name in (
"Reminders and Notifications",
"Secure Message",
"Security and Authentication",
"Voicemail Call and Missed Call Notifications",
"E-Signature",
"Financial Communications"
)
)
or (
length(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities,
.name not in ("org", "recipient", "sender")
),
.name
)
) > 0
and all(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities,
.name not in ("org", "recipient", "sender")
),
.name
),
.name in ("request", "financial", "urgency")
)
)
)
and not any(ml.nlu_classifier(body.current_thread.text).topics,
.name in (
"Advertising and Promotions",
"Newsletters and Digests",
"News and Current Events",
"Travel and Transportation"
)
)
// check only the first line of the email
and any(regex.iextract(body.current_thread.text, "^[^\r\n]*"),
length(.full_match) < 500
and strings.ilike(strings.replace_confusables(.full_match),
"*safe content*",
"*safe sender*",
"*trusted sender*",
"secure share" // strict match to avoid FPs
)
and not regex.icontains(.full_match,
"add.{0,50} to.{0,50}(address book|safe senders? list)"
)
)
Detection Logic
Scope: inbound message.
Detects messages containing credential theft language combined with social engineering topics like secure messages, notifications, or authentication alerts. The rule specifically identifies emails that deceptively claim to be from a 'safe sender' or contain 'safe content' in the first line, which is a common tactic used to bypass security filters and gain user trust.
- inbound message
- any(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence != "low" )
any of:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name in ( "Reminders and Notifications", "Secure Message", "Security and Authentication", "Voicemail Call and Missed Call Notifications", "E-Signature", "Financial Communications" ) )
all of:
- length(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities, .name not in ("org", "recipient", "sender") ), .name ) ) > 0
- all(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities, .name not in ("org", "recipient", "sender") ), .name ), .name in ("request", "financial", "urgency") )
not:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name in ( "Advertising and Promotions", "Newsletters and Digests", "News and Current Events", "Travel and Transportation" ) )
- any(regex.iextract(body.current_thread.text, "^[^\r\n]*"), length(.full_match) < 500 and strings.ilike(strings.replace_confusables(.full_match), "*safe content*", "*safe sender*", "*trusted sender*", "secure share" // strict match to avoid FPs ) and not regex.icontains(.full_match, "add.{0,50} to.{0,50}(address book|safe senders? list)" ) )
Inspects: body.current_thread.text, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, regex.iextract, strings.ilike, strings.replace_confusables.
Indicators Matched (15)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | cred_theft |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Reminders and Notifications |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Secure Message |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Security and Authentication |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Voicemail Call and Missed Call Notifications |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | E-Signature |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Financial Communications |
distinct(...)[].name | member | request |
distinct(...)[].name | member | financial |
distinct(...)[].name | member | urgency |
regex.iextract | regex | ^[^\r\n]* |
strings.ilike | substring | *safe content* |
3 more
strings.ilike | substring | *safe sender* |
strings.ilike | substring | *trusted sender* |
strings.ilike | substring | secure share |
Stages and Predicates
Stage 1: mql_rule
and
or
and
length func_call "length(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities,\n .name not in (\"org\", \"recipient\", \"sender\")\n ),\n .name\n )\n ) > 0"
macro "all(distinct(filter(ml.nlu_classifier(body.current_thread.text).entities,\n .name not in (\"org\", \"recipient\", \"sender\")\n ),\n .name\n ),\n .name in (\"request\", \"financial\", \"urgency\")\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name in (\n \"Reminders and Notifications\",\n \"Secure Message\",\n \"Security and Authentication\",\n \"Voicemail Call and Missed Call Notifications\",\n \"E-Signature\",\n \"Financial Communications\"\n )\n )"
not
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name in (\n \"Advertising and Promotions\",\n \"Newsletters and Digests\",\n \"News and Current Events\",\n \"Travel and Transportation\"\n )\n)"
type.inbound eq "true"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name == \"cred_theft\" and .confidence != \"low\"\n)"
macro "any(regex.iextract(body.current_thread.text, \"^[^\\r\\n]*\"),\n length(.full_match) < 500\n and strings.ilike(strings.replace_confusables(.full_match),\n \"*safe content*\",\n \"*safe sender*\",\n \"*trusted sender*\",\n \"secure share\" // strict match to avoid FPs\n )\n and not regex.icontains(.full_match,\n \"add.{0,50} to.{0,50}(address book|safe senders? list)\"\n )\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
CVE-2023-5631 - Roundcube Webmail XSS via crafted SVG
#Body HTML contains an exploit for CVE-2023-5631, a vulnerability in Roundcube Webmail that allows stored XSS via an HTML e-mail message with a crafted SVG document.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Malware/Ransomware |
| Tactics and techniques | Evasion, Exploit, HTML smuggling, Scripting |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and length(attachments) == 0
and strings.ilike(body.html.raw,
'*use href="data:image/svg+xml;base64,PHN2Zy*#*'
)
Detection Logic
Scope: inbound message.
Body HTML contains an exploit for CVE-2023-5631, a vulnerability in Roundcube Webmail that allows stored XSS via an HTML e-mail message with a crafted SVG document.
- inbound message
- length(attachments) == 0
- body.html.raw matches '*use href="data:image/svg+xml;base64,PHN2Zy*#*'
Inspects: body.html.raw, type.inbound. Sensors: strings.ilike.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
strings.ilike | substring | *use href="data:image/svg+xml;base64,PHN2Zy*#* |
Stages and Predicates
Stage 1: mql_rule
and
attachments length_compare "0"
body.html.raw wildcard "*use href=\"data:image/svg+xml;base64,PHN2Zy*#*"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | wildcard |
| field:"body.html.raw" kind:wildcard |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Extortion / sextortion (untrusted sender)
#Detects extortion and sextortion attempts by analyzing the email body text from an untrusted sender.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Extortion |
| Tactics and techniques | Social engineering, Spoofing |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and length(filter(body.links, .display_text is not null)) < 10
and not (
ml.nlu_classifier(body.current_thread.text).language == "english"
and any(ml.nlu_classifier(body.html.display_text).topics,
.name in (
"News and Current Events",
"Newsletters and Digests",
"Advertising and Promotions"
)
and .confidence in ("high", "medium")
)
)
and (
(
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents,
(.name == "extortion" and .confidence == "high")
)
and (
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text
)
).entities,
.name == "financial"
or (
.name is not null
and regex.icontains(.text,
"cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s"
)
)
)
or any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text
)
).topics,
.name == "Financial Communications" and .confidence != "low"
)
)
)
// catches extortion content delivered as inline base64 images
or (
(body.current_thread.text is null or length(body.current_thread.text) < 100)
and any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
.name == "extortion" and .confidence == "high"
)
and (
any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities,
.name == "financial"
)
or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,
.name == "Financial Communications" and .confidence != "low"
)
)
)
// manual indicators failsafe
or 3 of (
// malware terms
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess)"
),
// actions recorded
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent)"
),
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)"
),
// a timeframe to pay
regex.icontains(strings.replace_confusables(body.current_thread.text),
'[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])',
'(?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]?',
'set a timer'
),
// a promise from the actor
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:pe[rŗ]manently|will|I''ll) delete|([rŗ]emove|destroy) (?:[\p{L}\p{M}\p{N}]+\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?)'
),
// a threat from the actor
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:\bsen[dt]|forward|expose|share)\s*(?:[\p{L}\p{N}]+\s*){0,5}\s*to\s*(?:[\p{L}\p{N}]+\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\b)'
),
// bitcoin language (excluding newsletters)
(
regex.icontains(strings.replace_confusables(body.current_thread.text),
'[bḆḂ]i[tṯ][cĉƈ][oöة]i[nņɲň]|\bbtc\b|blockchain'
)
// negate cryptocurrency newsletters
and not (
any(body.links,
strings.icontains(.display_text, "unsubscribe")
and (
strings.icontains(.href_url.path, "unsubscribe")
// handle mimecast URL rewrites
or (
.href_url.domain.root_domain == 'mimecastprotect.com'
and strings.icontains(.href_url.query_params,
sender.email.domain.root_domain
)
)
)
)
)
),
(
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:contact the police|(?:bitcoin|\bbtc\b).{0,20}(?:wallet|address))'
)
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(?:0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b'
)
),
regex.icontains(strings.replace_confusables(body.current_thread.text),
'bc1q.{0,50}\b'
),
(
regex.count(body.current_thread.text,
'[\x{0300}-\x{036F}\x{1AB0}-\x{1AFF}\x{1DC0}-\x{1DFF}\x{0100}-\x{024F}\x{1E00}-\x{1EFF}]'
) > 20
and length(body.current_thread.links) == 0
)
)
)
and (
not profile.by_sender().solicited
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
or any(headers.hops, any(.fields, .name == "X-Google-Group-Id"))
// many extortion emails spoof sender domains and fail sender authentication
or (
not headers.auth_summary.dmarc.pass
or headers.auth_summary.dmarc.pass is null
or not headers.auth_summary.spf.pass
)
)
// negate legit bounce backs
and not any(ml.nlu_classifier(body.current_thread.text).topics,
.name in ("Bounce Back and Delivery Failure Notifications")
)
// negate legit forwards and replies
and not (
(subject.is_reply or subject.is_forward)
and length(body.previous_threads) > 0
and (length(headers.references) > 0 or headers.in_reply_to is not null)
)
// negate benign newsletters that mention cyber extortion
and not (
any(body.links,
strings.icontains(.display_text, "unsubscribe")
and strings.icontains(.href_url.path, "unsubscribe")
)
// newsletters are typically longer than the average extortion script
and length(body.current_thread.text) > 2000
)
and length(body.current_thread.text) < 8000
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
Detection Logic
Scope: inbound message.
Detects extortion and sextortion attempts by analyzing the email body text from an untrusted sender.
- inbound message
- length(filter(body.links, .display_text is not null)) < 10
not:
all of:
- ml.nlu_classifier(body.current_thread.text).language == "english"
- any(ml.nlu_classifier(body.html.display_text).topics, .name in ( "News and Current Events", "Newsletters and Digests", "Advertising and Promotions" ) and .confidence in ("high", "medium") )
any of:
all of:
- any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents, (.name == "extortion" and .confidence == "high") )
any of:
- any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text ) ).entities, .name == "financial" or ( .name is not null and regex.icontains(.text, "cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s" ) ) )
- any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text ) ).topics, .name == "Financial Communications" and .confidence != "low" )
all of:
any of:
- body.current_thread.text is missing
- length(body.current_thread.text) < 100
- any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents, .name == "extortion" and .confidence == "high" )
any of:
- any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities, .name == "financial" )
- any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics, .name == "Financial Communications" and .confidence != "low" )
at least 3 of:
- regex.icontains(strings.replace_confusables(body.current_thread.text), "(?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess)" )
- regex.icontains(strings.replace_confusables(body.current_thread.text), "(?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent)" )
- regex.icontains(strings.replace_confusables(body.current_thread.text), "(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)" )
- regex.icontains(strings.replace_confusables(body.current_thread.text), '[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])', '(?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]?', 'set a timer' )
- regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:pe[rŗ]manently|will|I''ll) delete|([rŗ]emove|destroy) (?:[\p{L}\p{M}\p{N}]+\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?)' )
- regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:\bsen[dt]|forward|expose|share)\s*(?:[\p{L}\p{N}]+\s*){0,5}\s*to\s*(?:[\p{L}\p{N}]+\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\b)' )
all of:
- regex.icontains(strings.replace_confusables(body.current_thread.text), '[bḆḂ]i[tṯ][cĉƈ][oöة]i[nņɲň]|\bbtc\b|blockchain' )
not:
any of
body.linkswhere all hold:- .display_text contains 'unsubscribe'
any of:
- .href_url.path contains 'unsubscribe'
all of:
- .href_url.domain.root_domain is 'mimecastprotect.com'
- strings.icontains(.href_url.query_params, sender.email.domain.root_domain )
all of:
- regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:contact the police|(?:bitcoin|\bbtc\b).{0,20}(?:wallet|address))' )
- regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(?:0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b' )
- regex.icontains(strings.replace_confusables(body.current_thread.text), 'bc1q.{0,50}\b' )
all of:
- regex.count(body.current_thread.text, '[\x{0300}-\x{036F}\x{1AB0}-\x{1AFF}\x{1DC0}-\x{1DFF}\x{0100}-\x{024F}\x{1E00}-\x{1EFF}]' ) > 20
- length(body.current_thread.links) == 0
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of
headers.hopswhere:any of
.fieldswhere:- .name is 'X-Google-Group-Id'
any of:
not:
- headers.auth_summary.dmarc.pass
- headers.auth_summary.dmarc.pass is missing
not:
- headers.auth_summary.spf.pass
not:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name in ("Bounce Back and Delivery Failure Notifications") )
not:
all of:
any of:
- subject.is_reply
- subject.is_forward
- length(body.previous_threads) > 0
any of:
- length(headers.references) > 0
- headers.in_reply_to is set
not:
all of:
any of
body.linkswhere all hold:- .display_text contains 'unsubscribe'
- .href_url.path contains 'unsubscribe'
- length(body.current_thread.text) > 2000
- length(body.current_thread.text) < 8000
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
Inspects: body.current_thread.links, body.current_thread.text, body.html.display_text, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, body.links[].href_url.path, body.links[].href_url.query_params, body.previous_threads, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.in_reply_to, headers.references, sender.email.domain.root_domain, subject.is_forward, subject.is_reply, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.nlu_classifier, profile.by_sender, regex.count, regex.icontains, strings.icontains, strings.replace_confusables. Reference lists: $high_trust_sender_root_domains.
Indicators Matched (23)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents[].name | equals | extortion |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents[].confidence | equals | high |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities[].name | equals | financial |
regex.icontains | regex | cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topics[].name | equals | Financial Communications |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].name | equals | extortion |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidence | equals | high |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities[].name | equals | financial |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics[].name | equals | Financial Communications |
regex.icontains | regex | (?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess) |
regex.icontains | regex | (?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent) |
regex.icontains | regex | (?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat) |
11 more
regex.icontains | regex | [ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ]) |
regex.icontains | regex | (?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]? |
regex.icontains | regex | set a timer |
regex.icontains | regex | (?:pe[rŗ]manently|will|I'll) delete|([rŗ]emove|destroy) (?:[\p{L}\p{M}\p{N}]+\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?) |
regex.icontains | regex | (?:\bsen[dt]|forward|expose|share)\s*(?:[\p{L}\p{N}]+\s*){0,5}\s*to\s*(?:[\p{L}\p{N}]+\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\b) |
regex.icontains | regex | [bḆḂ]i[tṯ][cĉƈ][oöة]i[nņɲň]|\bbtc\b|blockchain |
regex.icontains | regex | (?:contact the police|(?:bitcoin|\bbtc\b).{0,20}(?:wallet|address)) |
regex.icontains | regex | (?:\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(?:0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b |
regex.icontains | regex | bc1q.{0,50}\b |
regex.count | regex | [\x{0300}-\x{036F}\x{1AB0}-\x{1AFF}\x{1DC0}-\x{1DFF}\x{0100}-\x{024F}\x{1E00}-\x{1EFF}] |
headers.hops[].fields[].name | equals | X-Google-Group-Id |
Stages and Predicates
Stage 1: mql_rule
and
not
and
any(body.links)
and
body.links.display_text contains "unsubscribe"
body.links.href_url.path contains "unsubscribe"
body.current_thread.text length_compare "2000"
or
and
or
body.current_thread.text is_null
body.current_thread.text length_compare "100"
or
macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities,\n .name == \"financial\"\n )"
macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,\n .name == \"Financial Communications\" and .confidence != \"low\"\n )"
macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,\n .name == \"extortion\" and .confidence == \"high\"\n )"
and
or
macro "any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text\n )\n ).topics,\n .name == \"Financial Communications\" and .confidence != \"low\"\n )"
macro "any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text\n )\n ).entities,\n .name == \"financial\"\n or (\n .name is not null\n and regex.icontains(.text,\n \"cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s\"\n )\n )\n )"
macro "any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents,\n (.name == \"extortion\" and .confidence == \"high\")\n )"
macro "3 of (\n // malware terms\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n \"(?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess)\"\n ),\n // actions recorded\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n \"(?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent)\"\n ),\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n \"(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)\"\n ),\n // a timeframe to pay\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n '[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])',\n '(?:one|tw[oờȍ]|2|th[rŗ]ee|\\d) [dḍ][aảǡą]y[sṣ]?',\n 'set a timer'\n ),\n // a promise from the actor\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n '(?:pe[rŗ]manently|will|I''ll) delete|([rŗ]emove|destroy) (?:[\\p{L}\\p{M}\\p{N}]+\\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?)'\n ),\n // a threat from the actor\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n '(?:\\bsen[dt]|forward|expose|share)\\s*(?:[\\p{L}\\p{N}]+\\s*){0,5}\\s*to\\s*(?:[\\p{L}\\p{N}]+\\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\\b)'\n ),\n // bitcoin language (excluding newsletters)\n (\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n '[bḆḂ]i[tṯ][cĉƈ][oöة]i[nņɲň]|\\bbtc\\b|blockchain'\n )\n // negate cryptocurrency newsletters\n and not (\n any(body.links,\n strings.icontains(.display_text, \"unsubscribe\")\n and (\n strings.icontains(.href_url.path, \"unsubscribe\")\n // handle mimecast URL rewrites\n or (\n .href_url.domain.root_domain == 'mimecastprotect.com'\n and strings.icontains(.href_url.query_params,\n sender.email.domain.root_domain\n )\n )\n )\n )\n )\n ),\n (\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n '(?:contact the police|(?:bitcoin|\\bbtc\\b).{0,20}(?:wallet|address))'\n )\n and regex.icontains(strings.replace_confusables(body.current_thread.text),\n '(?:\\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\\b)|\\bX[1-9A-HJ-NP-Za-km-z]{33}\\b|\\b(?:0x[a-fA-F0-9]{40})\\b|\\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\\b|\\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\\b'\n )\n ),\n regex.icontains(strings.replace_confusables(body.current_thread.text),\n 'bc1q.{0,50}\\b'\n ),\n (\n regex.count(body.current_thread.text,\n '[\\x{0300}-\\x{036F}\\x{1AB0}-\\x{1AFF}\\x{1DC0}-\\x{1DFF}\\x{0100}-\\x{024F}\\x{1E00}-\\x{1EFF}]'\n ) > 20\n and length(body.current_thread.links) == 0\n )\n )"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
any(headers.hops)
any(headers.hops.fields)
headers.hops.fields.name eq "X-Google-Group-Id"
and
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
headers.auth_summary.dmarc.pass eq "true"
not
headers.auth_summary.spf.pass eq "true"
not
profile.by_sender func_call "profile.by_sender().solicited"
headers.auth_summary.dmarc.pass is_null
not
and
or
headers.in_reply_to is_not_null
headers.references length_compare "0"
or
subject.is_forward eq "true"
subject.is_reply eq "true"
body.previous_threads length_compare "0"
not
and
ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language == \"english\""
macro "any(ml.nlu_classifier(body.html.display_text).topics,\n .name in (\n \"News and Current Events\",\n \"Newsletters and Digests\",\n \"Advertising and Promotions\"\n )\n and .confidence in (\"high\", \"medium\")\n )"
not
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name in (\"Bounce Back and Delivery Failure Notifications\")\n)"
body.current_thread.text length_compare "8000"
length func_call "length(filter(body.links, .display_text is not null)) < 10"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
body.links | array_any | excludes:body.links | |
body.current_thread.text | length_compare | 2000 | excludes:body.current_thread.text field:"body.current_thread.text" value:"2000" |
headers.in_reply_to | is_not_null | excludes:headers.in_reply_to | |
headers.references | length_compare | 0 | excludes:headers.references field:"headers.references" value:"0" |
subject.is_forward | eq | true | excludes:subject.is_forward field:"subject.is_forward" value:"true" |
subject.is_reply | eq | true | excludes:subject.is_reply field:"subject.is_reply" value:"true" |
body.previous_threads | length_compare | 0 | excludes:body.previous_threads field:"body.previous_threads" value:"0" |
Honorific greeting BEC attempt with sender and reply-to mismatch
#Detects generic BEC/Fraud scams by analyzing text within the email body from mismatched senders with other suspicious indicators.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Free email provider, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// mismatched sender (From) and Reply-to + freemail
and (
length(headers.reply_to) > 0
and all(headers.reply_to,
.email.domain.root_domain != sender.email.domain.root_domain
and .email.domain.root_domain in $free_email_providers
)
)
// use of honorific
and regex.icontains(body.current_thread.text,
'(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\.?[ \t]+'
)
// BEC-themed language
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("bec", "advance_fee")
)
and any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "request"
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
and (
(
profile.by_sender().prevalence in ("new", "outlier")
and not profile.by_sender().solicited
)
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
)
and not profile.by_sender().any_messages_benign
Detection Logic
Scope: inbound message.
Detects generic BEC/Fraud scams by analyzing text within the email body from mismatched senders with other suspicious indicators.
- inbound message
all of:
- length(headers.reply_to) > 0
all of
headers.reply_towhere all hold:- .email.domain.root_domain is not sender.email.domain.root_domain
- .email.domain.root_domain in $free_email_providers
- body.current_thread.text matches '(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\\.?[ \\t]+'
all of:
- any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("bec", "advance_fee") )
- any(ml.nlu_classifier(body.current_thread.text).entities, .name == "request" )
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
any of:
all of:
- profile.by_sender().prevalence in ("new", "outlier")
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
not:
- profile.by_sender().any_messages_benign
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.reply_to, headers.reply_to[].email.domain.root_domain, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains. Reference lists: $free_email_providers, $high_trust_sender_root_domains.
Indicators Matched (4)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | (?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\.?[ \t]+ |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | bec |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | advance_fee |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | request |
Stages and Predicates
Stage 1: mql_rule
and
or
and
not
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
and
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
and
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().prevalence in (\"new\", \"outlier\")"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
body.current_thread.text regex_match "(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev)\\.?[ \\t]+"
headers.reply_to length_compare "0"
type.inbound eq "true"
macro "all(headers.reply_to,\n .email.domain.root_domain != sender.email.domain.root_domain\n and .email.domain.root_domain in $free_email_providers\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"request\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"bec\", \"advance_fee\")\n )"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"(?:Mr|Mrs|Ms|Miss|Dr|Prof|Sir|Lady|Rev).?[ \t]+" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
HTML smuggling with atob in message body
#Detects if the email body HTML contains the document write or insertAdjacentHTML method and atob function call. This technique has been observed leading to credential phishing.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, Malware/Ransomware |
| Tactics and techniques | HTML smuggling |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (length(body.plain.raw) < 200 or body.plain.raw is null)
and regex.icontains(body.html.raw,
"document.{0,10}(write|insertAdjacentHTML).{0,10}atob"
)
Detection Logic
Scope: inbound message.
Detects if the email body HTML contains the document write or insertAdjacentHTML method and atob function call. This technique has been observed leading to credential phishing.
- inbound message
any of:
- length(body.plain.raw) < 200
- body.plain.raw is missing
- body.html.raw matches 'document.{0,10}(write|insertAdjacentHTML).{0,10}atob'
Inspects: body.html.raw, body.plain.raw, type.inbound. Sensors: regex.icontains.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | document.{0,10}(write|insertAdjacentHTML).{0,10}atob |
Stages and Predicates
Stage 1: mql_rule
and
or
body.plain.raw is_null
body.plain.raw length_compare "200"
body.html.raw regex_match "document.{0,10}(write|insertAdjacentHTML).{0,10}atob"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | regex_match |
| field:"body.html.raw" kind:regex_match value:"document.{0,10}(write|insertAdjacentHTML).{0,10}atob" |
body.plain.raw | is_null | field:"body.plain.raw" kind:is_null | |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
HTML: Template placeholders or recipient email in element class attributes
#Detects inbound messages where HTML element class attributes contain either unfilled template placeholders (e.g., {email}, {RECIPIENT_EMAIL}, {domain}) or the recipient's actual email address — optionally wrapped in curly braces. This pattern indicates a bulk-sending infrastructure that failed to substitute personalization tokens, or one that embeds recipient identifiers directly into HTML class names for tracking or evasion purposes. Observed samples follow a consistent pattern: subjects contain numeric identifiers flanking the recipient's email address, and senders vary across unrelated domains, suggesting a coordinated operation targeting multiple organizations including technology and fitness brands.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, BEC/Fraud |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
// observed unpopulated template variables in class names
any(html.xpath(body.html, "//*/@class").nodes,
strings.contains(.raw, '{')
and strings.contains(.raw, '}')
and regex.icontains(.raw,
'\{\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\s]?EMAIL)\s*\}'
)
)
// check where class names _are_ the email address, or contain the email address are wrapped in { } or start/end with { or }
or any(recipients.to,
.email.email != ""
and any(html.xpath(body.html, "//*/@class").nodes,
.raw =~ ..email.email
or .raw =~ strings.concat("{", ..email.email, "}")
or .raw =~ strings.concat("{", ..email.email)
or .raw =~ strings.concat(..email.email, "}")
)
)
)
Detection Logic
Scope: inbound message.
Detects inbound messages where HTML element class attributes contain either unfilled template placeholders (e.g., {email}, {RECIPIENT_EMAIL}, {domain}) or the recipient's actual email address — optionally wrapped in curly braces. This pattern indicates a bulk-sending infrastructure that failed to substitute personalization tokens, or one that embeds recipient identifiers directly into HTML class names for tracking or evasion purposes. Observed samples follow a consistent pattern: subjects contain numeric identifiers flanking the recipient's email address, and senders vary across unrelated domains, suggesting a coordinated operation targeting multiple organizations including technology and fitness brands.
- inbound message
any of:
- any(html.xpath(body.html, "//*/@class").nodes, strings.contains(.raw, '{') and strings.contains(.raw, '}') and regex.icontains(.raw, '\{\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\s]?EMAIL)\s*\}' ) )
any of
recipients.towhere all hold:- .email.email is not ''
- any(html.xpath(body.html, "//*/@class").nodes, .raw =~ ..email.email or .raw =~ strings.concat("{", ..email.email, "}") or .raw =~ strings.concat("{", ..email.email) or .raw =~ strings.concat(..email.email, "}") )
Inspects: body.html, recipients.to, recipients.to[].email.email, type.inbound. Sensors: html.xpath, regex.icontains, strings.concat, strings.contains.
Indicators Matched (3)
| Field | Match | Value |
|---|---|---|
strings.contains | substring | { |
strings.contains | substring | } |
regex.icontains | regex | \{\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\s]?EMAIL)\s*\} |
Stages and Predicates
Stage 1: mql_rule
and
or
any(recipients.to)
and
recipients.to.email.email ne ""
macro "any(html.xpath(body.html, \"//*/@class\").nodes,\n .raw =~ ..email.email\n or .raw =~ strings.concat(\"{\", ..email.email, \"}\")\n or .raw =~ strings.concat(\"{\", ..email.email)\n or .raw =~ strings.concat(..email.email, \"}\")\n )"
macro "any(html.xpath(body.html, \"//*/@class\").nodes,\n strings.contains(.raw, '{')\n and strings.contains(.raw, '}')\n and regex.icontains(.raw,\n '\\{\\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\\s]?EMAIL)\\s*\\}'\n )\n )"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Investor solicitation with organization targeting
#Detects messages targeting organizations with investment solicitations that specifically reference the recipient's organization by extracting the organization name and matching it to the recipient's email domain.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
// subject contains recipient's org name
any(recipients.to,
strings.icontains(subject.subject, .email.domain.sld)
and regex.imatch(.email.domain.sld, '.{2,}')
)
or
// body extracts org name matching recipient domain
any(regex.extract(body.current_thread.text,
'(?P<org>[a-zA-Z]{2,20})\s(?:recently\s)?came to our attention'
),
any(recipients.to,
strings.icontains(.email.domain.domain, ..named_groups["org"])
)
)
)
and any(headers.reply_to,
.email.domain.root_domain != sender.email.domain.root_domain
)
// greeting uses recipient's email local_part
and any(recipients.to,
(
strings.icontains(body.current_thread.text,
strings.concat("Dear ", .email.local_part)
)
or any(regex.extract(.email.local_part, '^(?P<first>[^._]+)'),
strings.icontains(body.current_thread.text,
strings.concat("Dear ",
.named_groups["first"]
)
)
)
)
)
// financial/investment cold outreach language
and (
2 of (
strings.icontains(body.current_thread.text, "alternative investments"),
strings.icontains(body.current_thread.text, "raising capital"),
strings.icontains(body.current_thread.text, "came to our attention"),
strings.icontains(body.current_thread.text, "private markets"),
strings.icontains(body.current_thread.text, "fundraising"),
strings.icontains(body.current_thread.text, "investment opportunities"),
strings.icontains(body.current_thread.text, "introductory"),
strings.icontains(body.current_thread.text, "commitment size"),
strings.icontains(body.current_thread.text, "ultra-high-net-worth"),
strings.icontains(body.current_thread.text, "deployed capital"),
strings.icontains(body.current_thread.text, "value creation"),
strings.icontains(body.current_thread.text, "capital planning")
)
or (
any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "Financial Communications"
)
and any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "Out of Band Pivot"
)
and any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "B2B Cold Outreach"
)
)
)
Detection Logic
Scope: inbound message.
Detects messages targeting organizations with investment solicitations that specifically reference the recipient's organization by extracting the organization name and matching it to the recipient's email domain.
- inbound message
any of:
any of
recipients.towhere all hold:- strings.icontains(subject.subject, .email.domain.sld)
- .email.domain.sld matches '.{2,}'
- any(regex.extract(body.current_thread.text, '(?P<org>[a-zA-Z]{2,20})\s(?:recently\s)?came to our attention' ), any(recipients.to, strings.icontains(.email.domain.domain, ..named_groups["org"]) ) )
any of
headers.reply_towhere:- .email.domain.root_domain is not sender.email.domain.root_domain
any of
recipients.towhere any holds:- strings.icontains(body.current_thread.text, strings.concat("Dear ", .email.local_part) )
- any(regex.extract(.email.local_part, '^(?P<first>[^._]+)'), strings.icontains(body.current_thread.text, strings.concat("Dear ", .named_groups["first"] ) ) )
any of:
at least 2 of 12: body.current_thread.text contains any of 12 patterns
alternative investmentsraising capitalcame to our attentionprivate marketsfundraisinginvestment opportunitiesintroductorycommitment sizeultra-high-net-worthdeployed capitalvalue creationcapital planning
all of:
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Financial Communications" )
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Out of Band Pivot" )
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "B2B Cold Outreach" )
Inspects: body.current_thread.text, headers.reply_to, headers.reply_to[].email.domain.root_domain, recipients.to, recipients.to[].email.domain.domain, recipients.to[].email.domain.sld, recipients.to[].email.local_part, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.extract, regex.imatch, strings.concat, strings.icontains.
Indicators Matched (18)
| Field | Match | Value |
|---|---|---|
regex.imatch | regex | .{2,} |
regex.extract | regex | (?P<org>[a-zA-Z]{2,20})\s(?:recently\s)?came to our attention |
regex.extract | regex | ^(?P<first>[^._]+) |
strings.icontains | substring | alternative investments |
strings.icontains | substring | raising capital |
strings.icontains | substring | came to our attention |
strings.icontains | substring | private markets |
strings.icontains | substring | fundraising |
strings.icontains | substring | investment opportunities |
strings.icontains | substring | introductory |
strings.icontains | substring | commitment size |
strings.icontains | substring | ultra-high-net-worth |
6 more
strings.icontains | substring | deployed capital |
strings.icontains | substring | value creation |
strings.icontains | substring | capital planning |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Financial Communications |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Out of Band Pivot |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | B2B Cold Outreach |
Stages and Predicates
Stage 1: mql_rule
and
or
any(recipients.to)
and
recipients.to.email.domain.sld regex_match ".{2,}"
strings.icontains func_call "strings.icontains(subject.subject, .email.domain.sld)"
macro "any(regex.extract(body.current_thread.text,\n '(?P<org>[a-zA-Z]{2,20})\\s(?:recently\\s)?came to our attention'\n ),\n any(recipients.to,\n strings.icontains(.email.domain.domain, ..named_groups[\"org\"])\n )\n )"
any(recipients.to)
or
strings.icontains func_call "strings.icontains(body.current_thread.text,\n strings.concat(\"Dear \", .email.local_part)\n )"
macro "any(regex.extract(.email.local_part, '^(?P<first>[^._]+)'),\n strings.icontains(body.current_thread.text,\n strings.concat(\"Dear \",\n .named_groups[\"first\"]\n )\n )\n )"
or
and
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"B2B Cold Outreach\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"Out of Band Pivot\"\n )"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"Financial Communications\"\n )"
macro "2 of (\n strings.icontains(body.current_thread.text, \"alternative investments\"),\n strings.icontains(body.current_thread.text, \"raising capital\"),\n strings.icontains(body.current_thread.text, \"came to our attention\"),\n strings.icontains(body.current_thread.text, \"private markets\"),\n strings.icontains(body.current_thread.text, \"fundraising\"),\n strings.icontains(body.current_thread.text, \"investment opportunities\"),\n strings.icontains(body.current_thread.text, \"introductory\"),\n strings.icontains(body.current_thread.text, \"commitment size\"),\n strings.icontains(body.current_thread.text, \"ultra-high-net-worth\"),\n strings.icontains(body.current_thread.text, \"deployed capital\"),\n strings.icontains(body.current_thread.text, \"value creation\"),\n strings.icontains(body.current_thread.text, \"capital planning\")\n )"
any(headers.reply_to)
headers.reply_to.email.domain.root_domain cross_field_compare "sender.email.domain.root_domain"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Job scam (unsolicited sender)
#Detects job scam attempts by analyzing the message body text from an unsolicited sender.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("job_scam") and .confidence == "high"
)
)
and (
any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "financial"
)
or strings.icontains(body.current_thread.text, "salary package")
or strings.icontains(body.current_thread.text, "kindly")
or (
(
any(ml.nlu_classifier(body.current_thread.text).entities,
.name in ("greeting", "salutation")
)
or sender.email.domain.root_domain in $free_email_providers
)
and (
(
length(recipients.to) == 0
or length(recipients.bcc) > 0
or (
all(recipients.to, .email.domain.valid == false)
and all(recipients.cc, .email.domain.valid == false)
)
)
)
)
)
// negating income / job verification senders
and not (
sender.email.domain.root_domain in ('loandepot.com', 'sofi.com')
and headers.auth_summary.dmarc.pass
)
and (
not profile.by_sender().solicited
or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign
Detection Logic
Scope: inbound message.
Detects job scam attempts by analyzing the message body text from an unsolicited sender.
- inbound message
- ( any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("job_scam") and .confidence == "high" ) )
any of:
- any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial" )
- body.current_thread.text contains 'salary package'
- body.current_thread.text contains 'kindly'
all of:
any of:
- any(ml.nlu_classifier(body.current_thread.text).entities, .name in ("greeting", "salutation") )
- sender.email.domain.root_domain in $free_email_providers
any of:
- length(recipients.to) == 0
- length(recipients.bcc) > 0
all of:
all of
recipients.towhere:- .email.domain.valid is False
all of
recipients.ccwhere:- .email.domain.valid is False
not:
all of:
- sender.email.domain.root_domain in ('loandepot.com', 'sofi.com')
- headers.auth_summary.dmarc.pass
any of:
not:
- profile.by_sender().solicited
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, recipients.bcc, recipients.cc, recipients.cc[].email.domain.valid, recipients.to, recipients.to[].email.domain.valid, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, strings.icontains. Reference lists: $free_email_providers.
Indicators Matched (7)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | member | job_scam |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | equals | high |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | financial |
strings.icontains | substring | salary package |
strings.icontains | substring | kindly |
ml.nlu_classifier(body.current_thread.text).entities[].name | member | greeting |
ml.nlu_classifier(body.current_thread.text).entities[].name | member | salutation |
Stages and Predicates
Stage 1: mql_rule
and
or
and
or
and
macro "all(recipients.cc, .email.domain.valid == false)"
macro "all(recipients.to, .email.domain.valid == false)"
recipients.bcc length_compare "0"
recipients.to length_compare "0"
or
sender.email.domain.root_domain macro "sender.email.domain.root_domain in free_email_providers"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name in (\"greeting\", \"salutation\")\n )"
body.current_thread.text contains "kindly"
body.current_thread.text contains "salary package"
macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n .name == \"financial\"\n )"
not
and
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain in ["loandepot.com", "sofi.com"]
or
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
type.inbound eq "true"
macro "(\n any(ml.nlu_classifier(body.current_thread.text).intents,\n .name in (\"job_scam\") and .confidence == \"high\"\n )\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | contains |
| field:"body.current_thread.text" kind:contains |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
sender.email.domain.root_domain | in | loandepot.com, sofi.com | excludes:sender.email.domain.root_domain field:"sender.email.domain.root_domain" value:"loandepot.com" field:"sender.email.domain.root_domain" value:"sofi.com" |
Link: Self-sent PDF lure with subject correlation
#Detects messages sent from a user to themselves containing bold PDF links where the link text correlates with the subject line or sender domain, potentially indicating a compromised account or social engineering technique.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud, Credential Phishing |
| Tactics and techniques | Social engineering, Evasion |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// self sender
and (
length(recipients.to) == 1
and recipients.to[0].email.email == sender.email.email
)
// bold a tags ending in PDF
and any(html.xpath(body.html, '//a[./b]').nodes,
strings.iends_with(.display_text, ".pdf")
and (
// subject appears as the .pdf link
any(regex.extract(subject.base, '(?P<word>\w+)'),
strings.contains(..display_text, .named_groups["word"])
)
// OR sender domain appears as the pdf link
or strings.icontains(.display_text, sender.email.domain.sld)
)
// we should NOT match urls
and strings.parse_url(.display_text, strict=false).url is null
and not any(.links, strings.iends_with(.href_url.path, '.pdf'))
)
Detection Logic
Scope: inbound message.
Detects messages sent from a user to themselves containing bold PDF links where the link text correlates with the subject line or sender domain, potentially indicating a compromised account or social engineering technique.
- inbound message
all of:
- length(recipients.to) == 1
- recipients.to[0].email.email is sender.email.email
- any(html.xpath(body.html, '//a[./b]').nodes, strings.iends_with(.display_text, ".pdf") and ( // subject appears as the .pdf link any(regex.extract(subject.base, '(?P<word>\w+)'), strings.contains(..display_text, .named_groups["word"]) ) // OR sender domain appears as the pdf link or strings.icontains(.display_text, sender.email.domain.sld) ) // we should NOT match urls and strings.parse_url(.display_text, strict=false).url is null and not any(.links, strings.iends_with(.href_url.path, '.pdf')) )
Inspects: body.html, recipients.to, recipients.to[0].email.email, sender.email.domain.sld, sender.email.email, subject.base, type.inbound. Sensors: html.xpath, regex.extract, strings.contains, strings.icontains, strings.iends_with, strings.parse_url.
Indicators Matched (2)
| Field | Match | Value |
|---|---|---|
strings.iends_with | suffix | .pdf |
regex.extract | regex | (?P<word>\w+) |
Stages and Predicates
Stage 1: mql_rule
and
recipients.to length_compare "1"
recipients.to[0].email.email cross_field_compare "sender.email.email"
type.inbound eq "true"
macro "any(html.xpath(body.html, '//a[./b]').nodes,\n strings.iends_with(.display_text, \".pdf\")\n and (\n // subject appears as the .pdf link\n any(regex.extract(subject.base, '(?P<word>\\w+)'),\n strings.contains(..display_text, .named_groups[\"word\"])\n )\n // OR sender domain appears as the pdf link\n or strings.icontains(.display_text, sender.email.domain.sld)\n )\n // we should NOT match urls\n and strings.parse_url(.display_text, strict=false).url is null\n and not any(.links, strings.iends_with(.href_url.path, '.pdf'))\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Self-impersonation: Sender matches recipient with bolded name and suspicious link
#Detects messages where the sender's email address matches the recipient's email address, with the sender's display name appearing in bold text and a suspicious 'Read the Message' link present in the body.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
// sender matches recipients
and (
length(recipients.to) == 1
and recipients.to[0].email.email == sender.email.email
)
// sender in current thread BOLD
and any(html.xpath(body.html, '//b').nodes,
.display_text == sender.display_name
)
// we want the dashed html element to contain a link, and that link to include part of the subject (the subject is the org)
and any(html.xpath(body.html,
'//table//td[contains(@style, "border-style: dashed") and contains(@style, "border-width: 1pt")]//a[./b]'
).nodes,
any(regex.extract(subject.base, '(?P<word>\w+)'),
any(..links,
strings.icontains(.href_url.url, ..named_groups["word"])
)
)
)
Detection Logic
Scope: inbound message.
Detects messages where the sender's email address matches the recipient's email address, with the sender's display name appearing in bold text and a suspicious 'Read the Message' link present in the body.
- inbound message
all of:
- length(recipients.to) == 1
- recipients.to[0].email.email is sender.email.email
- any(html.xpath(body.html, '//b').nodes, .display_text == sender.display_name )
- any(html.xpath(body.html, '//table//td[contains(@style, "border-style: dashed") and contains(@style, "border-width: 1pt")]//a[./b]' ).nodes, any(regex.extract(subject.base, '(?P<word>\w+)'), any(..links, strings.icontains(.href_url.url, ..named_groups["word"]) ) ) )
Inspects: body.html, recipients.to, recipients.to[0].email.email, sender.display_name, sender.email.email, subject.base, type.inbound. Sensors: html.xpath, regex.extract, strings.icontains.
Indicators Matched (1)
| Field | Match | Value |
|---|---|---|
regex.extract | regex | (?P<word>\w+) |
Stages and Predicates
Stage 1: mql_rule
and
recipients.to length_compare "1"
recipients.to[0].email.email cross_field_compare "sender.email.email"
type.inbound eq "true"
macro "any(html.xpath(body.html, '//b').nodes,\n .display_text == sender.display_name\n)"
macro "any(html.xpath(body.html,\n '//table//td[contains(@style, \"border-style: dashed\") and contains(@style, \"border-width: 1pt\")]//a[./b]'\n ).nodes,\n any(regex.extract(subject.base, '(?P<word>\\w+)'),\n any(..links,\n strings.icontains(.href_url.url, ..named_groups[\"word\"])\n )\n )\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
URL with Unicode U+2044 (⁄) or U+2215 (∕) characters
#Body of the message, or any links, contain the Unicode U+2044 (⁄) or U+2215 (∕) characters inside a URL.
Threat Classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
Rule Body
type.inbound
and (
regex.icontains(body.plain.raw,
'https?:\/\/[^\s⁄∕]+(?:\/[^\s⁄∕]+)*[⁄∕][^\s⁄∕]+'
)
or any(body.links, strings.contains(.href_url.url, '⁄', '∕'))
)
Detection Logic
Scope: inbound message.
Body of the message, or any links, contain the Unicode U+2044 (⁄) or U+2215 (∕) characters inside a URL.
- inbound message
any of:
- body.plain.raw matches 'https?:\\/\\/[^\\s⁄∕]+(?:\\/[^\\s⁄∕]+)*[⁄∕][^\\s⁄∕]+'
any of
body.linkswhere:.href_url.url contains any of 2 patterns
⁄∕
Inspects: body.links, body.links[].href_url.url, body.plain.raw, type.inbound. Sensors: regex.icontains, strings.contains.
Indicators Matched (3)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | https?:\/\/[^\s⁄∕]+(?:\/[^\s⁄∕]+)*[⁄∕][^\s⁄∕]+ |
strings.contains | substring | ⁄ |
strings.contains | substring | ∕ |
Stages and Predicates
Stage 1: mql_rule
and
or
any(body.links)
or
body.links.href_url.url contains "⁄"
body.links.href_url.url contains "∕"
body.plain.raw regex_match "https?:\\/\\/[^\\s⁄∕]+(?:\\/[^\\s⁄∕]+)*[⁄∕][^\\s⁄∕]+"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.plain.raw | regex_match |
| field:"body.plain.raw" kind:regex_match value:"https?:\/\/[^\s⁄∕]+(?:\/[^\s⁄∕]+)*[⁄∕][^\s⁄∕]+" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |