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"

Related rules

to-top