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) < 5
 29    )
 30    // or a reply or forward in a thread that mentions website or screenshots
 31    or (
 32      (length(subject.base) < 5 or subject.is_reply or subject.is_forward)
 33      and any(body.previous_threads,
 34              regex.icontains(strings.replace_confusables(.text),
 35                              "(?:screenshot|website)"
 36              )
 37      )
 38    )
 39  )
 40  // body structure and content patterns
 41  and (
 42    // Single thread with no links
 43    (
 44      length(filter(body.current_thread.links,
 45                    not (.href_url.scheme == "mailto" and .parser == "plain")
 46             )
 47      ) == 0
 48      and length(body.previous_threads) == 0
 49      // short message between 20 and 500 chars
 50      and 20 < length(body.current_thread.text) < 500
 51      // service offering keywords
 52      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 53                          "(?:screenshot|error list|plan|quote|rank|professional|price|mistake|visibility|improvement|review|emailed.{0,10}more details)"
 54      )
 55      // generic greeting
 56      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 57                          'h(?:i|ello|ey)\b'
 58      )
 59      // problem or urgency keywords
 60      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 61                          '(?:error|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|glitch|send you|SEO)'
 62      )
 63      // website or page mention
 64      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 65                          "(?:site|website|page|package|SEO)"
 66      )
 67    )
 68    // Single thread with unsubscribe link or $org_domains link
 69    or (
 70      length(body.links) <= 3
 71      and (
 72        // unsubscribe mailto link
 73        regex.icontains(body.html.raw, "mailto:*[++unsubscribe@]")
 74        // or link to found in org_domains
 75        or any(body.links, .href_url.domain.root_domain in~ $org_domains)
 76      )
 77      and length(body.previous_threads) == 0
 78      // short message between 20 and 500 chars
 79      and 20 < length(body.current_thread.text) < 500
 80      // service offering keywords
 81      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 82                          "(?:screenshot|error list|plan|quote|rank|professional|price|mistake)"
 83      )
 84      // generic greeting
 85      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 86                          '(?:h(?:i|ello|ey)|morning)\b'
 87      )
 88      // problem or urgency keywords
 89      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 90                          '(?:error|report|issues|website|repair|redesign|upgrade|Google\s+.{0,15}find it|send you|SEO)'
 91      )
 92      // website or page mention
 93      and regex.icontains(strings.replace_confusables(body.current_thread.text),
 94                          "(?:site|website|page|package|SEO)"
 95      )
 96    )
 97    // Multiple thread messages
 98    or (
 99      length(body.links) == 0
100      // small thread with less than 5 messages
101      and length(body.previous_threads) < 5
102      // check previous messages for spam characteristics
103      and any(body.previous_threads,
104              // short previous messages less than 400 chars
105              length(.text) < 400
106              and (
107                // generic greeting
108                regex.icontains(strings.replace_confusables(.text),
109                                '(?:h(?:i|ello|ey)|morning)\b'
110                )
111                // service offering keywords
112                and regex.icontains(strings.replace_confusables(.text),
113                                    '(?:\berror(?:\s+list)?\b|screenshot|report|plan)'
114                )
115                // previous threads written in English
116                and ml.nlu_classifier(.text).language == "english"
117              )
118      )
119    )
120  )  
121tags:
122  - "Attack surface reduction"
123attack_types:
124  - "Spam"
125detection_methods:
126  - "Content analysis"
127  - "Sender analysis"
128  - "Natural Language Understanding"
129id: "122ea794-f619-5f29-acb2-83261d8f81fc"

Related rules

to-top