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.
Sublime rule (View on GitHub)
1name: "Spam: Website errors solicitation"
2description: "This rule detects messages claiming to have identified errors on a website. The messages typically offer to send pricing or information upon request."
3type: "rule"
4severity: "low"
5source: |
6 type.inbound
7 and not profile.by_sender().solicited
8 // no attachments
9 and length(attachments) == 0
10 // subject must contain SEO or web dev spam keywords or be short
11 and (
12 (
13 // SEO or web development service keywords
14 regex.icontains(strings.replace_confusables(subject.subject),
15 '(?:proposal|cost|estimate|error|bug|audit|screenshot|strategy|rankings|issues|fix|website|design|review|price)'
16 )
17 or regex.icontains(subject.base,
18 '[^\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}][\x{2600}-\x{27BF}\x{1F300}-\x{1F9FF}]\x{FE0F}?$'
19 )
20 // report and follow up keywords
21 or (
22 strings.icontains(strings.replace_confusables(subject.subject), "report")
23 and regex.icontains(strings.replace_confusables(body.current_thread.text),
24 "(?:free|send you|can i send|may i send|let me know|interested|get back to me|reply back|just reply)"
25 )
26 )
27 // short subject
28 or length(subject.base) < 7
29 or regex.icontains(subject.base, '[.?!-]{4,}')
30 )
31 // or a reply or forward in a thread that mentions website or screenshots
32 or (
33 (length(subject.base) < 5 or subject.is_reply or subject.is_forward)
34 and any(body.previous_threads,
35 regex.icontains(strings.replace_confusables(.text),
36 "(?:screenshot|website)"
37 )
38 )
39 )
40 )
41 // body structure and content patterns
42 and (
43 // Single thread with no links
44 (
45 length(filter(body.current_thread.links,
46 not (.href_url.scheme == "mailto" and .parser == "plain")
47 )
48 ) == 0
49 and length(body.previous_threads) == 0
50 // short message between 20 and 500 chars
51 and (
52 20 < length(body.current_thread.text) < 500
53 or any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
54 .name == "disclaimer"
55 ),
56 .text
57 ),
58 20 < (length(body.current_thread.text) - length(.)) < 500
59 )
60 )
61 // service offering keywords
62 and regex.icontains(strings.replace_confusables(body.current_thread.text),
63 '(?:screenshot|errors? (?:list|report)|plan|quote|rank|professional|price|mistake|visibility|improvement|review|emailed.{0,10}more details|(?:may|can|shall|should) i (?:email|send|share|forward|show)(?:\s+you)?.{0,15}(?:the|more|those|these|some)?\s*(?:details|info(?:rmation)?|report|screenshots?|list))'
64 )
65 // generic greeting
66 and regex.icontains(strings.replace_confusables(body.current_thread.text),
67 'h(?:i|ello|ey)\b'
68 )
69 // problem or urgency keywords
70 and regex.icontains(strings.replace_confusables(body.current_thread.text),
71 '(?:errors?|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|glitch|send you|SEO|broken)'
72 )
73 // website or page mention
74 and regex.icontains(strings.replace_confusables(body.current_thread.text),
75 "(?:site|website|page|package|SEO)"
76 )
77 )
78 // Single thread with unsubscribe link or $org_domains link
79 or (
80 length(body.links) <= 3
81 and (
82 // unsubscribe mailto link
83 regex.icontains(body.html.raw, "mailto:*[++unsubscribe@]")
84 // or link to found in org_domains
85 or any(body.links, .href_url.domain.root_domain in~ $org_domains)
86 )
87 and length(body.previous_threads) == 0
88 // short message between 20 and 500 chars
89 and 20 < length(body.current_thread.text) < 500
90 // service offering keywords
91 and regex.icontains(strings.replace_confusables(body.current_thread.text),
92 "(?:screenshot|error list|plan|quote|rank|professional|price|mistake)"
93 )
94 // generic greeting
95 and regex.icontains(strings.replace_confusables(body.current_thread.text),
96 '(?:h(?:i|ello|ey)|morning)\b'
97 )
98 // problem or urgency keywords
99 and regex.icontains(strings.replace_confusables(body.current_thread.text),
100 '(?:error|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|send you|SEO)'
101 )
102 // website or page mention
103 and regex.icontains(strings.replace_confusables(body.current_thread.text),
104 "(?:site|website|page|package|SEO)"
105 )
106 )
107 // Multiple thread messages
108 or (
109 length(body.links) == 0
110 // small thread with less than 5 messages
111 and length(body.previous_threads) < 5
112 // check previous messages for spam characteristics
113 and any(body.previous_threads,
114 // short previous messages less than 400 chars
115 length(.text) < 400
116 and (
117 // generic greeting
118 regex.icontains(strings.replace_confusables(.text),
119 '(?:h(?:i|ello|ey)|morning)\b'
120 )
121 // service offering keywords
122 and regex.icontains(strings.replace_confusables(.text),
123 '(?:\berror(?:\s+list)?\b|screenshot|report|plan)'
124 )
125 // previous threads written in English
126 and ml.nlu_classifier(.text).language == "english"
127 )
128 )
129 )
130 )
131tags:
132 - "Attack surface reduction"
133attack_types:
134 - "Spam"
135detection_methods:
136 - "Content analysis"
137 - "Sender analysis"
138 - "Natural Language Understanding"
139id: "122ea794-f619-5f29-acb2-83261d8f81fc"