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, '')) is 0
- .email.email is not sender.email.email
- sender.email.domain.tld in $suspicious_tlds
any of
['jp', 'jo']where:- strings.iends_with(sender.email.domain.tld)
all of:
- length(recipients.to) is 0
any of
headers.reply_towhere:- .email.domain.root_domain is not sender.email.domain.root_domain
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name is 'advance_fee'
- .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)"
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence in ["high", "medium"]
ml.nlu_classifier(body.current_thread.text).intents.name eq "advance_fee"
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)"
any(['jp', 'jo'])
strings.iends_with func_call "strings.iends_with(sender.email.domain.tld)"
macro "sender.email.domain.domain in free_email_providers"
macro "sender.email.domain.tld in suspicious_tlds"
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
attachments[0].file_name regex_match "payment|invoice|receipt|document|bank"
body.current_thread.text regex_match "[A-Z]{10,}"
or
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,}"
body.current_thread.text regex_match "zip file.{1,50}encrypted"
subject.subject contains "invoice attached"
subject.subject contains "new debit"
subject.subject contains "payment confirmation"
subject.subject contains "you have received"
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 of
ml.nlu_classifier(body.current_thread.text).topicswhere all hold:- .name is 'Financial Communications'
- .confidence is not 'low'
all of:
any of
ml.nlu_classifier(body.current_thread.text).topicswhere all hold:- .name is 'B2B Cold Outreach'
- .confidence is not '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
any(ml.nlu_classifier(body.current_thread.text).topics)
and
ml.nlu_classifier(body.current_thread.text).topics.confidence ne "low"
ml.nlu_classifier(body.current_thread.text).topics.name eq "B2B Cold Outreach"
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+%"
any(ml.nlu_classifier(body.current_thread.text).topics)
and
ml.nlu_classifier(body.current_thread.text).topics.confidence ne "low"
ml.nlu_classifier(body.current_thread.text).topics.name eq "Financial Communications"
or
sender.email.domain.tld eq "info"
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 of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .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) is 0
- headers.in_reply_to is missing
- headers.in_reply_to is missing
any of:
at least 3 of:
any of
[subject.subject, body.current_thread.text]where:- . matches '(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) is 1
any of
ml.nlu_classifier(body.current_thread.text).topicswhere all hold:- .name is 'Professional and Career Development'
- .confidence is 'high'
any of:
- length(recipients.to) is 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) is 0
any of
regex.extract(body.current_thread.text)where any holds:- strings.parse_email(.full_match).domain.domain in $free_email_providers
- 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
any(ml.nlu_classifier(body.current_thread.text).topics)
and
ml.nlu_classifier(body.current_thread.text).topics.confidence eq "high"
ml.nlu_classifier(body.current_thread.text).topics.name eq "Professional and Career Development"
or
recipients.to length_compare "0"
macro "all(recipients.to)"
ml.nlu_classifier(body.current_thread.text).topics length_compare "1"
any([subject.subject, body.current_thread.text])
[subject.subject, body.current_thread.text] regex_match "(full|part).time"
body.current_thread.text eq "100% legal"
body.current_thread.text match "commission"
body.current_thread.text match "company rep"
body.current_thread.text match "hourly"
body.current_thread.text match "job"
body.current_thread.text match "manager"
body.current_thread.text match "per hour"
body.current_thread.text match "prior experience"
body.current_thread.text regex_match "\\bHR\\b"
or
and
attachments length_compare "0"
macro "all(attachments)"
attachments length_compare "0"
any(regex.extract(body.current_thread.text))
or
strings.parse_email func_call "strings.parse_email(regex.extract(body.current_thread.text)[].full_match).domain.domain in free_email_providers"
strings.parse_email func_call "strings.parse_email(regex.extract(body.current_thread.text)[].full_match).domain.root_domain in free_email_providers"
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name in ["greeting", "salutation"]
or
macro "all(body.links)"
macro "sender.email.domain.root_domain in free_email_providers"
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:"\bHR\b" |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
body.html.raw | is_null | field:"body.html.raw" kind:is_null | |
headers.in_reply_to | is_null | field:"headers.in_reply_to" kind:is_null | |
subject.is_forward | eq |
| field:"subject.is_forward" kind:eq value:"true" |
subject.is_reply | eq |
| field:"subject.is_reply" kind:eq value:"true" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere:- .name is 'bec'
any of
ml.nlu_classifier(body.current_thread.text).topicswhere all hold:- .name in ('Financial Communications', 'Payment Information')
- .confidence is '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)
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
coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
any(ml.nlu_classifier(body.current_thread.text).topics)
and
ml.nlu_classifier(body.current_thread.text).topics.confidence eq "high"
ml.nlu_classifier(body.current_thread.text).topics.name in ["Financial Communications", "Payment Information"]
any(ml.nlu_classifier(body.current_thread.text).intents)
ml.nlu_classifier(body.current_thread.text).intents.name eq "bec"
network.whois func_call "network.whois(sender.email.domain).days_old < 30"
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.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Body: CSS clamp() font obfuscation with IP-based links
#Detects inbound messages using a CSS evasion technique where font-size or line-height properties are set using the clamp() function with very small or negative values — a method used to hide or manipulate rendered text and evade content-based detection. Messages matching this pattern also contain at least one hyperlink resolving directly to an IP address rather than a domain. Observed lures span a wide range of social engineering themes including urgent account alerts, financial offers, storage login codes, service cancellations, and renewal reminders.
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)?,'
)
and any(body.links, .href_url.ip.ip is not null)
)
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)?,'
)
and any(file.parse_eml(.).body.links, .href_url.ip.ip is not null)
)
)
Detection logic
Scope: inbound message.
Detects inbound messages using a CSS evasion technique where font-size or line-height properties are set using the clamp() function with very small or negative values — a method used to hide or manipulate rendered text and evade content-based detection. Messages matching this pattern also contain at least one hyperlink resolving directly to an IP address rather than a domain. Observed lures span a wide range of social engineering themes including urgent account alerts, financial offers, storage login codes, service cancellations, and renewal reminders.
- inbound message
any of:
all of:
- body.html.raw matches '(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,'
any of
body.linkswhere:- .href_url.ip.ip is set
any of
attachmentswhere all hold:any of:
- .content_type is 'message/rfc822'
- .file_extension is 'eml'
- file.parse_eml(.).body.html.raw matches '(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,'
any of
file.parse_eml(.).body.linkswhere:- .href_url.ip.ip is set
Inspects: attachments[].content_type, attachments[].file_extension, body.html.raw, body.links, body.links[].href_url.ip.ip, 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"
any(file.parse_eml(attachments).body.links)
file.parse_eml(attachments).body.links.href_url.ip.ip is_not_null
file.parse_eml(attachments[]).body.html.raw regex_match "(?:font-size|line-height):\\s*clamp\\s*\\(\\s*(?:-\\d+|0)(?:px|em|rem|pt)?,"
and
any(body.links)
body.links.href_url.ip.ip is_not_null
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 of
html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodeswhere all hold:- .raw matches 'clip-path:\\s*inset\\(\\s*100%'
- 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
any(html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodes)
and
html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodes.inner_text length_compare "150"
html.xpath(body.html, '//div[contains(@style,"clip-path")]').nodes.raw regex_match "clip-path:\\s*inset\\(\\s*100%"
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" |
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 of
regex.iextract(body.html.raw)where all hold:- .named_groups['n1'] is .named_groups['n2']
- .named_groups['u1'] is .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
any(regex.iextract(body.html.raw))
and
regex.iextract(body.html.raw).named_groups['n1'] cross_field_compare "regex.iextract(body.html.raw).named_groups['n2']"
regex.iextract(body.html.raw).named_groups['u1'] cross_field_compare "regex.iextract(body.html.raw).named_groups['u2']"
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" |
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)
- 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)"
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")
)
)
)
// 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) is 0
- headers.in_reply_to is missing
all of:
- length(recipients.to) is 1
- length(recipients.cc) is 0
- sender.email.email is recipients.to[0].email.email
- length(recipients.to) is 1
- length(recipients.cc) is 0
- length(recipients.bcc) is 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
ml.nlu_classifier(body.current_thread.text).intentswhere:- .name in ('cred_theft', 'bec')
- 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)
not:
all of:
- coalesce(headers.auth_summary.dmarc.pass)
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.icontains. Reference lists: $high_trust_sender_root_domains.
Indicators matched (10)
| 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 |
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"
coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
or
and
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,}"
any(ml.nlu_classifier(body.current_thread.text).intents)
ml.nlu_classifier(body.current_thread.text).intents.name in ["bec", "cred_theft"]
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
coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
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"
filter(body.current_thread.links, .href_url.domain.valid and .href_url.scheme in ('https', 'http') and .visible == True) length_compare "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"Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
body.current_thread.links | array_any | excludes:body.current_thread.links |
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 | |
sender.email.email | cross_field_compare |
| field:"sender.email.email" kind:cross_field_compare value:"recipients.to[0].email.email" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodeswhere:- .display_text is 'Important'
any of
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodeswhere:- .display_text is '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
any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes)
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes.display_text eq "Company"
any(html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes)
html.xpath(body.html, '//td[contains(@style, "background-color")]').nodes.display_text eq "Important"
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" |
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 of
ml.logo_detect(.).brandswhere:- .name starts with 'Microsoft'
any of
attachmentswhere all hold:- .file_type in $file_types_images
any of
file.explode(.)where:at least 2 of 20: .scan.ocr.raw matches any of 20 patterns
*password**unread messages**Shared Documents**expiration**office**expire**expiring**kindly**renew**review*emails failed**kicked out**prevented**storage quota**required now*cache**qr code**barcode**security update**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
any(file.explode(attachments))
or
file.explode(attachments[])[].scan.ocr.raw ends_with "required now"
file.explode(attachments[])[].scan.ocr.raw ends_with "review"
file.explode(attachments[])[].scan.ocr.raw match "Shared Documents"
file.explode(attachments[])[].scan.ocr.raw match "barcode"
file.explode(attachments[])[].scan.ocr.raw match "cache"
file.explode(attachments[])[].scan.ocr.raw match "emails failed"
file.explode(attachments[])[].scan.ocr.raw match "expiration"
file.explode(attachments[])[].scan.ocr.raw match "expire"
file.explode(attachments[])[].scan.ocr.raw match "expiring"
file.explode(attachments[])[].scan.ocr.raw match "kicked out"
file.explode(attachments[])[].scan.ocr.raw match "kindly"
file.explode(attachments[])[].scan.ocr.raw match "office"
file.explode(attachments[])[].scan.ocr.raw match "password"
file.explode(attachments[])[].scan.ocr.raw match "prevented"
file.explode(attachments[])[].scan.ocr.raw match "qr code"
file.explode(attachments[])[].scan.ocr.raw match "quarantine"
file.explode(attachments[])[].scan.ocr.raw match "renew"
file.explode(attachments[])[].scan.ocr.raw match "security update"
file.explode(attachments[])[].scan.ocr.raw match "storage quota"
file.explode(attachments[])[].scan.ocr.raw match "unread messages"
macro "attachments[].file_type in file_types_images"
any(attachments)
and
any(ml.logo_detect(attachments).brands)
ml.logo_detect(attachments).brands.name starts_with "Microsoft"
macro "attachments[].file_type in file_types_images"
any(body.links)
and
any(body.links.href_url.rewrite.encoders)
body.links.href_url.rewrite.encoders contains "open_redirect"
not
macro "body.links[].href_url.domain.root_domain in org_domains"
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"]
type.inbound eq "true"
macro "sender.email.domain.root_domain not in org_domains"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 |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name in ('bec')
- .confidence is '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)"
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
ml.nlu_classifier(body.current_thread.text).intents.name eq "bec"
type.inbound eq "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" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name in ('bec')
- .confidence is '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"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
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"
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
ml.nlu_classifier(body.current_thread.text).intents.name eq "bec"
type.inbound eq "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:" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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(attachments) == 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)'
)
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 of
map(...)where:- length(body.current_thread.text) - length(.) < 500
- length(attachments) is 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)'
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name in ('bec', 'advance_fee')
- .confidence is not 'low'
all of:
- length(body.current_thread.text) < 550
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere:- .name is 'bec'
any of
ml.nlu_classifier(sender.display_name).intentswhere:- .name is 'bec'
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .text contains '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) is 0
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.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.
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) |
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
or
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.text contains "kindly"
any(ml.nlu_classifier(body.current_thread.text).intents)
ml.nlu_classifier(body.current_thread.text).intents.name eq "bec"
any(ml.nlu_classifier(sender.display_name).intents)
ml.nlu_classifier(sender.display_name).intents.name eq "bec"
body.current_thread.text length_compare "550"
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence ne "low"
ml.nlu_classifier(body.current_thread.text).intents.name in ["advance_fee", "bec"]
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
not
profile.by_sender func_call "profile.by_sender().solicited"
profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
or
any(map(...))
macro "(length(body.current_thread.text) - length(map(...)[])) < 500"
body.current_thread.text length_compare "500"
not
profile.by_sender func_call "profile.by_sender().any_messages_benign"
attachments length_compare "0"
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)"
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(attachments) == 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:
- length(body.previous_threads) > 0
- length(body.previous_threads) < 3
- length(attachments) is 0
any of
body.previous_threadswhere all hold:any of:
- length(.text) < 500
any of
map(...)where:- 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 of
ml.nlu_classifier(.text).intentswhere all hold:- .name in ('bec', 'advance_fee')
- .confidence in ('medium', 'high')
all of:
any of
body.previous_threadswhere:- length(.text) < 550
any of:
any of
body.previous_threadswhere:any of
ml.nlu_classifier(.text).intentswhere:- .name is 'bec'
any of
ml.nlu_classifier(sender.display_name).intentswhere:- .name is 'bec'
any of
body.previous_threadswhere:any of
ml.nlu_classifier(.text).entitieswhere:- .text contains '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: 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: $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)
any(ml.nlu_classifier(body.previous_threads.text).entities)
ml.nlu_classifier(body.previous_threads.text).entities.text contains "kindly"
any(body.previous_threads)
any(ml.nlu_classifier(body.previous_threads.text).intents)
ml.nlu_classifier(body.previous_threads.text).intents.name eq "bec"
any(ml.nlu_classifier(sender.display_name).intents)
ml.nlu_classifier(sender.display_name).intents.name eq "bec"
any(body.previous_threads)
body.previous_threads.text length_compare "550"
any(body.previous_threads)
any(ml.nlu_classifier(body.previous_threads.text).intents)
and
ml.nlu_classifier(body.previous_threads[].text).intents[].confidence in ["high", "medium"]
ml.nlu_classifier(body.previous_threads[].text).intents[].name in ["advance_fee", "bec"]
any(body.previous_threads)
and
or
any(map(...))
macro "(length(body.previous_threads[].text) - length(map(...)[])) < 500"
body.previous_threads.text length_compare "500"
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"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
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"
attachments length_compare "0"
body.previous_threads length_compare "0"
body.previous_threads length_compare "3"
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) is 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 is False
- headers.mailer in ('Microsoft CDO for Windows 2000')
all of:
- length(recipients.to) is 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 of
ml.logo_detect(file.message_screenshot()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
- beta.ocr(file.message_screenshot()).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)'
- 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 of
file.explode(...)where all hold:at least 3 of:
- .scan.ocr.raw contains 'purchase'
- .scan.ocr.raw contains 'payment'
- .scan.ocr.raw contains 'transaction'
- .scan.ocr.raw contains 'subscription'
- .scan.ocr.raw contains 'antivirus'
- .scan.ocr.raw contains 'order'
- .scan.ocr.raw contains 'support'
- .scan.ocr.raw contains 'help line'
- .scan.ocr.raw contains 'receipt'
- .scan.ocr.raw contains 'invoice'
- .scan.ocr.raw contains 'call'
- .scan.ocr.raw contains 'helpdesk'
- .scan.ocr.raw contains 'cancel'
- .scan.ocr.raw contains 'renew'
- .scan.ocr.raw contains 'refund'
- .scan.ocr.raw matches '(?:reach|contact) us at'
- .scan.ocr.raw contains '+1'
- .scan.ocr.raw contains 'amount'
- .scan.ocr.raw contains 'charged'
- .scan.ocr.raw contains 'crypto'
- .scan.ocr.raw contains 'wallet address'
- .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
.scan.ocr.raw 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}
not:
- regex.icount(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3
not:
- .scan.ocr.raw matches '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
any(file.explode(...))
and
or
file.explode(...).scan.ocr.raw contains "+1"
file.explode(...).scan.ocr.raw contains "amount"
file.explode(...).scan.ocr.raw contains "antivirus"
file.explode(...).scan.ocr.raw contains "call"
file.explode(...).scan.ocr.raw contains "cancel"
file.explode(...).scan.ocr.raw contains "charged"
file.explode(...).scan.ocr.raw contains "crypto"
file.explode(...).scan.ocr.raw contains "help line"
file.explode(...).scan.ocr.raw contains "helpdesk"
file.explode(...).scan.ocr.raw contains "invoice"
file.explode(...).scan.ocr.raw contains "order"
file.explode(...).scan.ocr.raw contains "payment"
file.explode(...).scan.ocr.raw contains "purchase"
file.explode(...).scan.ocr.raw contains "receipt"
file.explode(...).scan.ocr.raw contains "refund"
file.explode(...).scan.ocr.raw contains "renew"
file.explode(...).scan.ocr.raw contains "subscription"
file.explode(...).scan.ocr.raw contains "support"
file.explode(...).scan.ocr.raw contains "transaction"
file.explode(...).scan.ocr.raw contains "wallet address"
file.explode(...).scan.ocr.raw regex_match "(?:reach|contact) us at"
file.explode(...).scan.ocr.raw regex_match "\\$\\d{3}\\.\\d{2}\\b"
or
file.explode(...).scan.ocr.raw regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
file.explode(...).scan.ocr.raw regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
not
file.explode(...).scan.ocr.raw regex_match "wrote:[\\r\\n]"
not
regex.icount func_call "regex.icount(file.explode(...)[].scan.ocr.raw, \"(?:from|to|sent|date|cc|subject):\") > 3"
and
or
body.current_thread.text contains "+1"
body.current_thread.text contains "amount"
body.current_thread.text contains "antivirus"
body.current_thread.text contains "call"
body.current_thread.text contains "cancel"
body.current_thread.text contains "charged"
body.current_thread.text contains "crypto"
body.current_thread.text contains "help line"
body.current_thread.text contains "invoice"
body.current_thread.text contains "order"
body.current_thread.text contains "payment"
body.current_thread.text contains "purchase"
body.current_thread.text contains "receipt"
body.current_thread.text contains "refund"
body.current_thread.text contains "renew"
body.current_thread.text contains "subscription"
body.current_thread.text contains "support"
body.current_thread.text contains "transaction"
body.current_thread.text contains "wallet address"
body.current_thread.text regex_match "(?:reach|contact) us at"
body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
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}"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
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
any(ml.logo_detect(file.message_screenshot()).brands)
ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Norton", "PayPal"]
beta.ocr(file.message_screenshot()).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)"
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)"
or
and
recipients.to length_compare "1"
macro "all(recipients.to)"
headers.mailer eq "Microsoft CDO for Windows 2000"
network.whois func_call "network.whois(sender.email.domain).found == false"
macro "sender.email.domain.root_domain in free_email_providers"
macro "sender.email.domain.tld in suspicious_tlds"
not
headers.message_id ends_with "@shopify.com>"
attachments length_compare "0"
body.current_thread.text length_compare "1750"
type.inbound eq "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>" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
beta.ocr(file.message_screenshot()).text | regex_match |
| field:"beta.ocr(file.message_screenshot()).text" kind:regex_match value:"(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)" |
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 |
headers.mailer | in |
| field:"headers.mailer" kind:in value:"Microsoft CDO for Windows 2000" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is 'urgency'
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is 'request'
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is '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"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
or
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name eq "financial"
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name eq "request"
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name eq "urgency"
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)"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*"
)
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name is 'cred_theft'
- .confidence is not 'low'
any of:
any of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .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 of
distinct(...)where:- .name in ('request', 'financial', 'urgency')
not:
any of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .name in ('Advertising and Promotions', 'Newsletters and Digests', 'News and Current Events', 'Travel and Transportation')
any of
regex.iextract(body.current_thread.text)where all hold:- length(.full_match) < 500
strings.replace_confusables(.full_match) matches any of 3 patterns
*safe content**safe sender**trusted sender*
not:
- .full_match matches '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 (14)
| 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* |
2 more
strings.ilike | substring | *safe sender* |
strings.ilike | substring | *trusted sender* |
Stages and Predicates
Stage 1: mql_rule
and
any(regex.iextract(body.current_thread.text))
and
not
regex.iextract(body.current_thread.text).full_match regex_match "add.{0,50} to.{0,50}(address book|safe senders? list)"
or
strings.replace_confusables(regex.iextract(body.current_thread.text)[].full_match) match "safe content"
strings.replace_confusables(regex.iextract(body.current_thread.text)[].full_match) match "safe sender"
strings.replace_confusables(regex.iextract(body.current_thread.text)[].full_match) match "trusted sender"
regex.iextract(body.current_thread.text).full_match length_compare "500"
or
and
distinct(filter(ml.nlu_classifier(body.current_thread.text).entities, .name not in ('org', 'recipient', 'sender')), .name) length_compare "0"
macro "all(distinct(...))"
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name in ["E-Signature", "Financial Communications", "Reminders and Notifications", "Secure Message", "Security and Authentication", "Voicemail Call and Missed Call Notifications"]
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence ne "low"
ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
not
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name in ["Advertising and Promotions", "News and Current Events", "Newsletters and Digests", "Travel and Transportation"]
type.inbound eq "true"Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
ml.nlu_classifier(body.current_thread.text).topics | array_any | excludes:ml.nlu_classifier(body.current_thread.text).topics |
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) is 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 is 'english'
any of
ml.nlu_classifier(body.html.display_text).topicswhere all hold:- .name in ('News and Current Events', 'Newsletters and Digests', 'Advertising and Promotions')
- .confidence in ('high', 'medium')
any of:
all of:
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intentswhere all hold:- .name is 'extortion'
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entitieswhere any holds:- .name is 'financial'
all of:
- .name is set
- .text matches 'cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s'
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topicswhere all hold:- .name is 'Financial Communications'
- .confidence is not 'low'
all of:
any of:
- body.current_thread.text is missing
- length(body.current_thread.text) < 100
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intentswhere all hold:- .name is 'extortion'
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entitieswhere:- .name is 'financial'
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topicswhere all hold:- .name is 'Financial Communications'
- .confidence is not 'low'
at least 3 of:
- strings.replace_confusables(body.current_thread.text) matches '(?:(?: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)'
- strings.replace_confusables(body.current_thread.text) matches '(?: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)'
- strings.replace_confusables(body.current_thread.text) matches '(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)'
strings.replace_confusables(body.current_thread.text) matches any of 3 patterns
[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])(?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]?set a timer
- strings.replace_confusables(body.current_thread.text) matches "(?: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?)"
- strings.replace_confusables(body.current_thread.text) matches '(?:\\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:
- strings.replace_confusables(body.current_thread.text) matches '[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)
all of:
- strings.replace_confusables(body.current_thread.text) matches '(?:contact the police|(?:bitcoin|\\bbtc\\b).{0,20}(?:wallet|address))'
- strings.replace_confusables(body.current_thread.text) matches '(?:\\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'
- strings.replace_confusables(body.current_thread.text) matches '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) is 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 of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .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
or
and
not
any(body.links)
and
or
and
body.links.href_url.domain.root_domain eq "mimecastprotect.com"
strings.icontains func_call "strings.icontains(body.links[].href_url.query_params)"
body.links.href_url.path contains "unsubscribe"
body.links.display_text contains "unsubscribe"
strings.replace_confusables(body.current_thread.text) regex_match "[bḆḂ]i[tṯ][cĉƈ][oöة]i[nņɲň]|\\bbtc\\b|blockchain"
and
or
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities)
or
and
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities.name is_not_null
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities.text regex_match "cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s"
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities.name eq "financial"
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topics)
and
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topics.confidence ne "low"
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topics.name eq "Financial Communications"
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents)
and
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents.confidence eq "high"
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents.name eq "extortion"
and
or
any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics)
and
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics.confidence ne "low"
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics.name eq "Financial Communications"
any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities)
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities.name eq "financial"
any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents)
and
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents.confidence eq "high"
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents.name eq "extortion"
or
body.current_thread.text is_null
body.current_thread.text length_compare "100"
and
body.current_thread.links length_compare "0"
regex.count func_call "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
strings.replace_confusables(body.current_thread.text) regex_match "(?:\\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"
strings.replace_confusables(body.current_thread.text) regex_match "(?:contact the police|(?:bitcoin|\\bbtc\\b).{0,20}(?:wallet|address))"
strings.replace_confusables(body.current_thread.text) regex_match "(?:(?: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)"
strings.replace_confusables(body.current_thread.text) regex_match "(?:\\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)"
strings.replace_confusables(body.current_thread.text) regex_match "(?:one|tw[oờȍ]|2|th[rŗ]ee|\\d) [dḍ][aảǡą]y[sṣ]?"
strings.replace_confusables(body.current_thread.text) regex_match "(?: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)"
strings.replace_confusables(body.current_thread.text) regex_match "(?: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?)"
strings.replace_confusables(body.current_thread.text) regex_match "(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)"
strings.replace_confusables(body.current_thread.text) regex_match "[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])"
strings.replace_confusables(body.current_thread.text) regex_match "bc1q.{0,50}\\b"
strings.replace_confusables(body.current_thread.text) regex_match "set a timer"
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"
not
and
any(ml.nlu_classifier(body.html.display_text).topics)
and
ml.nlu_classifier(body.html.display_text).topics.confidence in ["high", "medium"]
ml.nlu_classifier(body.html.display_text).topics.name in ["Advertising and Promotions", "News and Current Events", "Newsletters and Digests"]
ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language == english"
or
and
not
headers.auth_summary.dmarc.pass eq "true"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
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
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name eq "Bounce Back and Delivery Failure Notifications"
body.current_thread.text length_compare "8000"
filter(body.links, .display_text is not null) length_compare "10"
type.inbound eq "true"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" |
ml.nlu_classifier(body.html.display_text).topics | array_any | excludes:ml.nlu_classifier(body.html.display_text).topics | |
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" |
ml.nlu_classifier(body.current_thread.text).topics | array_any | excludes:ml.nlu_classifier(body.current_thread.text).topics |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | is_null | field:"body.current_thread.text" kind:is_null | |
headers.auth_summary.dmarc.pass | is_null | field:"headers.auth_summary.dmarc.pass" kind:is_null | |
strings.replace_confusables(body.current_thread.text) | regex_match |
| field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere:- .name in ('bec', 'advance_fee')
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is '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"
macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
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)"
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name eq "request"
any(ml.nlu_classifier(body.current_thread.text).intents)
ml.nlu_classifier(body.current_thread.text).intents.name in ["advance_fee", "bec"]
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)"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 of
html.xpath(body.html, '//*/@class').nodeswhere all hold:- .raw contains '{'
- .raw contains '}'
- .raw matches '\\{\\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\\s]?EMAIL)\\s*\\}'
any of
recipients.towhere all hold:- .email.email is not ''
any of
html.xpath(body.html, '//*/@class').nodeswhere any holds:- .raw is .email.email
- .raw is strings.concat('{', .email.email, '}')
- .raw is strings.concat('{', .email.email)
- .raw is 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
any(html.xpath(body.html, '//*/@class').nodes)
or
html.xpath(body.html, '//*/@class').nodes.raw cross_field_compare "recipients.to.email.email"
macro "html.xpath(body.html, '//*/@class').nodes[].raw =~ strings.concat('{', recipients.to[].email.email)"
macro "html.xpath(body.html, '//*/@class').nodes[].raw =~ strings.concat('{', recipients.to[].email.email, '}')"
macro "html.xpath(body.html, '//*/@class').nodes[].raw =~ strings.concat(recipients.to[].email.email, '}')"
recipients.to.email.email ne ""
any(html.xpath(body.html, '//*/@class').nodes)
and
html.xpath(body.html, '//*/@class').nodes.raw contains "{"
html.xpath(body.html, '//*/@class').nodes.raw contains "}"
html.xpath(body.html, '//*/@class').nodes.raw regex_match "\\{\\s*(?:domain|email|(?:RECIPIENT|SENDER)[_\\s]?EMAIL)\\s*\\}"
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 matches '.{2,}'
any of
regex.extract(body.current_thread.text)where:any of
recipients.towhere:- strings.icontains(.email.domain.domain)
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)
any of
regex.extract(.email.local_part)where:- strings.icontains(body.current_thread.text)
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 of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .name is 'Financial Communications'
any of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .name is 'Out of Band Pivot'
any of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .name is '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
and
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name eq "B2B Cold Outreach"
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name eq "Financial Communications"
any(ml.nlu_classifier(body.current_thread.text).topics)
ml.nlu_classifier(body.current_thread.text).topics.name eq "Out of Band Pivot"
body.current_thread.text contains "alternative investments"
body.current_thread.text contains "came to our attention"
body.current_thread.text contains "capital planning"
body.current_thread.text contains "commitment size"
body.current_thread.text contains "deployed capital"
body.current_thread.text contains "fundraising"
body.current_thread.text contains "introductory"
body.current_thread.text contains "investment opportunities"
body.current_thread.text contains "private markets"
body.current_thread.text contains "raising capital"
body.current_thread.text contains "ultra-high-net-worth"
body.current_thread.text contains "value creation"
or
any(recipients.to)
and
recipients.to.email.domain.sld regex_match ".{2,}"
strings.icontains func_call "strings.icontains(subject.subject)"
any(regex.extract(body.current_thread.text))
any(recipients.to)
strings.icontains func_call "strings.icontains(recipients.to[].email.domain.domain)"
any(recipients.to)
or
any(regex.extract(recipients.to.email.local_part))
strings.icontains func_call "strings.icontains(body.current_thread.text)"
strings.icontains func_call "strings.icontains(body.current_thread.text)"
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 |
|---|---|---|---|
body.current_thread.text | contains |
| field:"body.current_thread.text" kind:contains |
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 of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name in ('job_scam')
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is 'financial'
- body.current_thread.text contains 'salary package'
- body.current_thread.text contains 'kindly'
all of:
any of:
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name in ('greeting', 'salutation')
- sender.email.domain.root_domain in $free_email_providers
any of:
- length(recipients.to) is 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
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name in ["greeting", "salutation"]
macro "sender.email.domain.root_domain in free_email_providers"
or
and
macro "all(recipients.cc)"
macro "all(recipients.to)"
recipients.bcc length_compare "0"
recipients.to length_compare "0"
any(ml.nlu_classifier(body.current_thread.text).entities)
ml.nlu_classifier(body.current_thread.text).entities.name eq "financial"
body.current_thread.text contains "kindly"
body.current_thread.text contains "salary package"
not
and
headers.auth_summary.dmarc.pass eq "true"
sender.email.domain.root_domain in ["loandepot.com", "sofi.com"]
any(ml.nlu_classifier(body.current_thread.text).intents)
and
ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
ml.nlu_classifier(body.current_thread.text).intents.name eq "job_scam"
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"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" |
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" |
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) is 1
- recipients.to[0].email.email is sender.email.email
any of
html.xpath(body.html, '//a[./b]').nodeswhere all hold:- .display_text ends with '.pdf'
any of:
any of
regex.extract(subject.base)where:- strings.contains(.display_text)
- strings.icontains(.display_text)
- strings.parse_url(.display_text, strict=False).url is missing
not:
any of
.linkswhere:- .href_url.path ends with '.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
any(html.xpath(body.html, '//a[./b]').nodes)
and
not
any(html.xpath(body.html, '//a[./b]').nodes.links)
html.xpath(body.html, '//a[./b]').nodes.links.href_url.path ends_with ".pdf"
or
any(regex.extract(subject.base))
strings.contains func_call "strings.contains(html.xpath(body.html, '//a[./b]').nodes[].display_text)"
strings.icontains func_call "strings.icontains(html.xpath(body.html, '//a[./b]').nodes[].display_text)"
html.xpath(body.html, '//a[./b]').nodes.display_text ends_with ".pdf"
strings.parse_url(html.xpath(body.html, '//a[./b]').nodes[].display_text, strict=False).url is_null
recipients.to length_compare "1"
recipients.to[0].email.email cross_field_compare "sender.email.email"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
recipients.to[0].email.email | cross_field_compare |
| field:"recipients.to[0].email.email" kind:cross_field_compare value:"sender.email.email" |
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) is 1
- recipients.to[0].email.email is sender.email.email
any of
html.xpath(body.html, '//b').nodeswhere:- .display_text is sender.display_name
any of
html.xpath(body.html, '//table//td[contains(@style, "border-style: dashed") and contains(@style, "border-width: 1pt")]//a[./b]').nodeswhere:any of
regex.extract(subject.base)where:any of
.linkswhere:- strings.icontains(.href_url.url)
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
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))
any(html.xpath(body.html, '//table//td[contains(@style, "border-style: dashed") and contains(@style, "border-width: 1pt")]//a[./b]').nodes.links)
strings.icontains func_call "strings.icontains(html.xpath(body.html, '//table//td[contains(@style, \"border-style: dashed\") and contains(@style, \"border-width: 1pt\")]//a[./b]').nodes[].links[].href_url.url)"
any(html.xpath(body.html, '//b').nodes)
html.xpath(body.html, '//b').nodes.display_text cross_field_compare "sender.display_name"
recipients.to length_compare "1"
recipients.to[0].email.email cross_field_compare "sender.email.email"
type.inbound eq "true"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
recipients.to[0].email.email | cross_field_compare |
| field:"recipients.to[0].email.email" kind:cross_field_compare value:"sender.email.email" |
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" |