Detection rules › Sublime MQL
Spam: Website errors solicitation
This rule detects messages claiming to have identified errors on a website. The messages typically offer to send pricing or information upon request.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Spam |
Event coverage
Rule body MQL
type.inbound
and not profile.by_sender().solicited
// no attachments
and length(attachments) == 0
// subject must contain SEO or web dev spam keywords or be short
and (
(
// SEO or web development service keywords
regex.icontains(strings.replace_confusables(subject.subject),
'(?:proposal|cost|estimate|error|bug|audit|screenshot|strategy|rankings|issues|fix|website|design|review|price)'
)
or regex.icontains(subject.base,
'[^\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}][\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}]\x{FE0F}?$'
)
// report and follow up keywords
or (
strings.icontains(strings.replace_confusables(subject.subject), "report")
and regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:free|send you|can i send|may i send|let me know|interested|get back to me|reply back|just reply)"
)
)
// short subject
or length(subject.base) < 7
)
// or a reply or forward in a thread that mentions website or screenshots
or (
(length(subject.base) < 5 or subject.is_reply or subject.is_forward)
and any(body.previous_threads,
regex.icontains(strings.replace_confusables(.text),
"(?:screenshot|website)"
)
)
)
)
// body structure and content patterns
and (
// Single thread with no links
(
length(filter(body.current_thread.links,
not (.href_url.scheme == "mailto" and .parser == "plain")
)
) == 0
and length(body.previous_threads) == 0
// short message between 20 and 500 chars
and (
20 < length(body.current_thread.text) < 500
or any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
.name == "disclaimer"
),
.text
),
20 < (length(body.current_thread.text) - length(.)) < 500
)
)
// service offering keywords
and regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:screenshot|errors? (?:list|report)|plan|quote|rank|professional|price|mistake|visibility|improvement|review|emailed.{0,10}more details)"
)
// generic greeting
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'h(?:i|ello|ey)\b'
)
// problem or urgency keywords
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:errors?|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|glitch|send you|SEO|broken)'
)
// website or page mention
and regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:site|website|page|package|SEO)"
)
)
// Single thread with unsubscribe link or $org_domains link
or (
length(body.links) <= 3
and (
// unsubscribe mailto link
regex.icontains(body.html.raw, "mailto:*[++unsubscribe@]")
// or link to found in org_domains
or any(body.links, .href_url.domain.root_domain in~ $org_domains)
)
and length(body.previous_threads) == 0
// short message between 20 and 500 chars
and 20 < length(body.current_thread.text) < 500
// service offering keywords
and regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:screenshot|error list|plan|quote|rank|professional|price|mistake)"
)
// generic greeting
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:h(?:i|ello|ey)|morning)\b'
)
// problem or urgency keywords
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:error|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|send you|SEO)'
)
// website or page mention
and regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:site|website|page|package|SEO)"
)
)
// Multiple thread messages
or (
length(body.links) == 0
// small thread with less than 5 messages
and length(body.previous_threads) < 5
// check previous messages for spam characteristics
and any(body.previous_threads,
// short previous messages less than 400 chars
length(.text) < 400
and (
// generic greeting
regex.icontains(strings.replace_confusables(.text),
'(?:h(?:i|ello|ey)|morning)\b'
)
// service offering keywords
and regex.icontains(strings.replace_confusables(.text),
'(?:\berror(?:\s+list)?\b|screenshot|report|plan)'
)
// previous threads written in English
and ml.nlu_classifier(.text).language == "english"
)
)
)
)
Detection logic
Scope: inbound message.
This rule detects messages claiming to have identified errors on a website. The messages typically offer to send pricing or information upon request.
- inbound message
not:
- profile.by_sender().solicited
- length(attachments) is 0
any of:
any of:
- strings.replace_confusables(subject.subject) matches '(?:proposal|cost|estimate|error|bug|audit|screenshot|strategy|rankings|issues|fix|website|design|review|price)'
- subject.base matches '[^\\x{2600}-\\x{27BF}\\x{1F300}-\\x{1F9FF}][\\x{2600}-\\x{27BF}\\x{1F300}-\\x{1F9FF}]\\x{FE0F}?$'
all of:
- strings.replace_confusables(subject.subject) contains 'report'
- strings.replace_confusables(body.current_thread.text) matches '(?:free|send you|can i send|may i send|let me know|interested|get back to me|reply back|just reply)'
- length(subject.base) < 7
all of:
any of:
- length(subject.base) < 5
- subject.is_reply
- subject.is_forward
any of
body.previous_threadswhere:- strings.replace_confusables(.text) matches '(?:screenshot|website)'
any of:
all of:
- length(filter(body.current_thread.links, not .href_url.scheme == 'mailto' and .parser == 'plain')) is 0
- length(body.previous_threads) is 0
any of:
all of:
- length(body.current_thread.text) > 20
- length(body.current_thread.text) < 500
any of
map(...)where all hold:- 20 < length(body.current_thread.text) - length(.)
- length(body.current_thread.text) - length(.) < 500
- strings.replace_confusables(body.current_thread.text) matches '(?:screenshot|errors? (?:list|report)|plan|quote|rank|professional|price|mistake|visibility|improvement|review|emailed.{0,10}more details)'
- strings.replace_confusables(body.current_thread.text) matches 'h(?:i|ello|ey)\\b'
- strings.replace_confusables(body.current_thread.text) matches '(?:errors?|report|issues|website|repair|redesign|upgrade|Google\\s+.{0,15}find it|glitch|send you|SEO|broken)'
- strings.replace_confusables(body.current_thread.text) matches '(?:site|website|page|package|SEO)'
all of:
- length(body.links) ≤ 3
any of:
- body.html.raw matches 'mailto:*[++unsubscribe@]'
any of
body.linkswhere:- .href_url.domain.root_domain in $org_domains
- length(body.previous_threads) is 0
all of:
- length(body.current_thread.text) > 20
- length(body.current_thread.text) < 500
- strings.replace_confusables(body.current_thread.text) matches '(?:screenshot|error list|plan|quote|rank|professional|price|mistake)'
- strings.replace_confusables(body.current_thread.text) matches '(?:h(?:i|ello|ey)|morning)\\b'
- strings.replace_confusables(body.current_thread.text) matches '(?:error|report|issues|website|repair|redesign|upgrade|Google\\s+.{0,15}find it|send you|SEO)'
- strings.replace_confusables(body.current_thread.text) matches '(?:site|website|page|package|SEO)'
all of:
- length(body.links) is 0
- length(body.previous_threads) < 5
any of
body.previous_threadswhere all hold:- length(.text) < 400
all of:
- strings.replace_confusables(.text) matches '(?:h(?:i|ello|ey)|morning)\\b'
- strings.replace_confusables(.text) matches '(?:\\berror(?:\\s+list)?\\b|screenshot|report|plan)'
- ml.nlu_classifier(.text).language is 'english'
Inspects: body.current_thread.links, body.current_thread.links[].href_url.scheme, body.current_thread.links[].parser, body.current_thread.text, body.html.raw, body.links, body.links[].href_url.domain.root_domain, body.previous_threads, body.previous_threads[].text, subject.base, subject.is_forward, subject.is_reply, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, strings.icontains, strings.replace_confusables. Reference lists: $org_domains.
Indicators matched (17)
| Field | Match | Value |
|---|---|---|
regex.icontains | regex | (?:proposal|cost|estimate|error|bug|audit|screenshot|strategy|rankings|issues|fix|website|design|review|price) |
regex.icontains | regex | [^\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}][\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}]\x{FE0F}?$ |
strings.icontains | substring | report |
regex.icontains | regex | (?:free|send you|can i send|may i send|let me know|interested|get back to me|reply back|just reply) |
regex.icontains | regex | (?:screenshot|website) |
body.current_thread.links[].href_url.scheme | equals | mailto |
body.current_thread.links[].parser | equals | plain |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | disclaimer |
regex.icontains | regex | (?:screenshot|errors? (?:list|report)|plan|quote|rank|professional|price|mistake|visibility|improvement|review|emailed.{0,10}more details) |
regex.icontains | regex | h(?:i|ello|ey)\b |
regex.icontains | regex | (?:errors?|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|glitch|send you|SEO|broken) |
regex.icontains | regex | (?:site|website|page|package|SEO) |
5 more
regex.icontains | regex | mailto:*[++unsubscribe@] |
regex.icontains | regex | (?:screenshot|error list|plan|quote|rank|professional|price|mistake) |
regex.icontains | regex | (?:h(?:i|ello|ey)|morning)\b |
regex.icontains | regex | (?:error|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|send you|SEO) |
regex.icontains | regex | (?:\berror(?:\s+list)?\b|screenshot|report|plan) |