Detection rules › Sublime MQL

Sublime MQL rules: credential

Brand impersonation: Fake DocuSign HTML table not linking to DocuSign domains

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects HTML table elements that mimick DocuSign templates linking to non-DocuSign destinations. The rule negates high trusted sender domains and legitimate replies.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.html
  • body.links
  • headers
  • headers.hops
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) == 0
and (
  0 < length(body.links) < 10
  // ignore link count when the HTML is padded with whitespace
  // indicative of thread hijacking/copy-pasting
  or regex.icount(body.html.raw, '(<br\s*/?>[\s\n]*)') > 50
)
and (
  regex.icontains(body.html.raw, '<font size="[0-9]">DocuSign</font>')
  or regex.icontains(body.html.raw, '<span[^>]*style="[^"]*">DocuSign<\/span>')
  or regex.icontains(body.html.raw, '<strong>DocuSign</strong>')
  or regex.icontains(body.html.raw,
                     'D&#917540;&#917540;o&#917540;&#917540;c\x{FE00}uS&#917540;&#917540;i\x{FE00}gn'
  )
  or any(body.links, regex.icontains(.display_text, 'view.{0,3}doc'))
  or any(body.links, regex.contains(.display_text, '\bDOCUMENT'))
)
and (
  regex.icontains(body.html.raw, 'background:\s*rgb\(30,\s*76,\s*161\)')
  or regex.icontains(body.html.raw,
                     'background-color:\s*rgb\(30,\s*76,\s*161\)'
  )
  or regex.icontains(body.html.raw,
                     'background-color:\s*rgb\(61,\s*170,\s*73\)'
  )
  or regex.icontains(body.html.raw,
                     '<div[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>|<td[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>'
  )
  or regex.icontains(body.html.raw, 'background-color:#214e9f;')
  or regex.icontains(body.html.raw, 'background-color:#3260a7')
  or regex.icontains(body.html.raw,
                     '<table[^>]*cellspacing="0"[^>]*cellpadding="0"[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*<td[^>]*style="BACKGROUND:\s*rgb\(247,247,247\);\s*width:\s*[0-9]{2,3}px;\s*padding:20px;\s*margin:\s*[0-9]{2,3}px"[^>]*>.*<div[^>]*style="BACKGROUND:\s*rgb\(30,76,161\);\s*padding:[0-9]{2,3}px;\s*color:#EFEFEF"[^>]*align="center"[^>]*>.*DOCUMENT.*</a>'
  )
  // Docusign Blue Box template with button
  or (
    regex.icontains(body.html.raw,
                    '<(td|div)[^>]*style="[^"]*background(-color)?:\s*(#1e4ca1|rgb\(30,\s*76,\s*161\))[^"]*"[^>]*>'
    )
    and (
      regex.icontains(body.html.raw,
                      '<a[^>]*style="[^"]*background-color:\s*(#[A-Fa-f0-9]{6}|rgb\([^)]*\))[^"]*"[^>]*>.*?<span[^>]*>.*?<\/span>.*?<\/a>'
      )
      // white link with a border
      or (
        regex.icontains(body.html.raw,
                        '<a[^>]*style="[^"]*color:\s*(white|#fff|#ffffff|#FFF|#FFFFFF|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\)|rgba\(\s*255\s*,\s*255\s*,\s*255\s*,\s*[0-9.]+\s*\)|rgb\(\s*100%\s*,\s*100%\s*,\s*100%\s*\))[^"]*"[^>]*>.*?<\/a>'
        )
        and regex.icontains(body.html.raw,
                            '<a[^>]*style="[^"]*border:[^"]*"[^>]*>.*?<\/a>'
        )
      )
    )
  )
)
and any(body.links,
        not strings.ilike(.href_url.domain.root_domain, "docusign.*")
        and (
          .display_text is null or regex.contains(.display_text, '\bDOCUMENT')
        )
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

// negate legit replies
and not (length(headers.references) > 0 or headers.in_reply_to is not null)
and not profile.by_sender().any_messages_benign

// negate docusign X-Return-Path
and not any(headers.hops,
            .index == 0
            and any(.fields,
                    .name == "X-Return-Path"
                    and strings.ends_with(.value, "docusign.net")
            )
)

Detection logic

Scope: inbound message.

Detects HTML table elements that mimick DocuSign templates linking to non-DocuSign destinations. The rule negates high trusted sender domains and legitimate replies.

  1. inbound message
  2. length(attachments) is 0
  3. any of:
    • all of:
      • length(body.links) > 0
      • length(body.links) < 10
    • regex.icount(body.html.raw, '(<br\\s*/?>[\\s\\n]*)') > 50
  4. any of:
    • body.html.raw matches '<font size="[0-9]">DocuSign</font>'
    • body.html.raw matches '<span[^>]*style="[^"]*">DocuSign<\\/span>'
    • body.html.raw matches '<strong>DocuSign</strong>'
    • body.html.raw matches 'D&#917540;&#917540;o&#917540;&#917540;c\\x{FE00}uS&#917540;&#917540;i\\x{FE00}gn'
    • any of body.links where:
      • .display_text matches 'view.{0,3}doc'
    • any of body.links where:
      • .display_text matches '\\bDOCUMENT'
  5. any of:
    • body.html.raw matches 'background:\\s*rgb\\(30,\\s*76,\\s*161\\)'
    • body.html.raw matches 'background-color:\\s*rgb\\(30,\\s*76,\\s*161\\)'
    • body.html.raw matches 'background-color:\\s*rgb\\(61,\\s*170,\\s*73\\)'
    • body.html.raw matches '<div[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>|<td[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>'
    • body.html.raw matches 'background-color:#214e9f;'
    • body.html.raw matches 'background-color:#3260a7'
    • body.html.raw matches '<table[^>]*cellspacing="0"[^>]*cellpadding="0"[^>]*>\\s*<tbody[^>]*>\\s*<tr[^>]*>\\s*<td[^>]*style="BACKGROUND:\\s*rgb\\(247,247,247\\);\\s*width:\\s*[0-9]{2,3}px;\\s*padding:20px;\\s*margin:\\s*[0-9]{2,3}px"[^>]*>.*<div[^>]*style="BACKGROUND:\\s*rgb\\(30,76,161\\);\\s*padding:[0-9]{2,3}px;\\s*color:#EFEFEF"[^>]*align="center"[^>]*>.*DOCUMENT.*</a>'
    • all of:
      • body.html.raw matches '<(td|div)[^>]*style="[^"]*background(-color)?:\\s*(#1e4ca1|rgb\\(30,\\s*76,\\s*161\\))[^"]*"[^>]*>'
      • any of:
        • body.html.raw matches '<a[^>]*style="[^"]*background-color:\\s*(#[A-Fa-f0-9]{6}|rgb\\([^)]*\\))[^"]*"[^>]*>.*?<span[^>]*>.*?<\\/span>.*?<\\/a>'
        • all of:
          • body.html.raw matches '<a[^>]*style="[^"]*color:\\s*(white|#fff|#ffffff|#FFF|#FFFFFF|rgb\\(\\s*255\\s*,\\s*255\\s*,\\s*255\\s*\\)|rgba\\(\\s*255\\s*,\\s*255\\s*,\\s*255\\s*,\\s*[0-9.]+\\s*\\)|rgb\\(\\s*100%\\s*,\\s*100%\\s*,\\s*100%\\s*\\))[^"]*"[^>]*>.*?<\\/a>'
          • body.html.raw matches '<a[^>]*style="[^"]*border:[^"]*"[^>]*>.*?<\\/a>'
  6. any of body.links where all hold:
    • not:
      • .href_url.domain.root_domain matches 'docusign.*'
    • any of:
      • .display_text is missing
      • .display_text matches '\\bDOCUMENT'
  7. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • any of distinct(headers.hops) where:
        • .authentication_results.dmarc matches '*fail'
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains
  8. none of:
    • length(headers.references) > 0
    • headers.in_reply_to is set
  9. not:
    • profile.by_sender().any_messages_benign
  10. not:
    • any of headers.hops where all hold:
      • .index is 0
      • any of .fields where all hold:
        • .name is 'X-Return-Path'
        • .value ends with 'docusign.net'

Inspects: body.html.raw, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, headers.hops, headers.hops[].authentication_results.dmarc, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, headers.hops[].index, headers.in_reply_to, headers.references, sender.email.domain.root_domain, type.inbound. Sensors: profile.by_sender, regex.contains, regex.icontains, regex.icount, strings.ends_with, strings.ilike. Reference lists: $high_trust_sender_root_domains.

Indicators matched (19)

FieldMatchValue
regex.icountregex(<br\s*/?>[\s\n]*)
regex.icontainsregex<font size="[0-9]">DocuSign</font>
regex.icontainsregex<span[^>]*style="[^"]*">DocuSign<\/span>
regex.icontainsregex<strong>DocuSign</strong>
regex.icontainsregexD&#917540;&#917540;o&#917540;&#917540;c\x{FE00}uS&#917540;&#917540;i\x{FE00}gn
regex.icontainsregexview.{0,3}doc
regex.containsregex\bDOCUMENT
regex.icontainsregexbackground:\s*rgb\(30,\s*76,\s*161\)
regex.icontainsregexbackground-color:\s*rgb\(30,\s*76,\s*161\)
regex.icontainsregexbackground-color:\s*rgb\(61,\s*170,\s*73\)
regex.icontainsregex<div[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>|<td[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>
regex.icontainsregexbackground-color:#214e9f;
7 more
regex.icontainsregexbackground-color:#3260a7
regex.icontainsregex<table[^>]*cellspacing="0"[^>]*cellpadding="0"[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*<td[^>]*style="BACKGROUND:\s*rgb\(247,247,247\);\s*width:\s*[0-9]{2,3}px;\s*padding:20px;\s*margin:\s*[0-9]{2,3}px"[^>]*>.*<div[^>]*style="BACKGROUND:\s*rgb\(30,76,161\);\s*padding:[0-9]{2,3}px;\s*color:#EFEFEF"[^>]*align="center"[^>]*>.*DOCUMENT.*</a>
regex.icontainsregex<(td|div)[^>]*style="[^"]*background(-color)?:\s*(#1e4ca1|rgb\(30,\s*76,\s*161\))[^"]*"[^>]*>
regex.icontainsregex<a[^>]*style="[^"]*background-color:\s*(#[A-Fa-f0-9]{6}|rgb\([^)]*\))[^"]*"[^>]*>.*?<span[^>]*>.*?<\/span>.*?<\/a>
regex.icontainsregex<a[^>]*style="[^"]*color:\s*(white|#fff|#ffffff|#FFF|#FFFFFF|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\)|rgba\(\s*255\s*,\s*255\s*,\s*255\s*,\s*[0-9.]+\s*\)|rgb\(\s*100%\s*,\s*100%\s*,\s*100%\s*\))[^"]*"[^>]*>.*?<\/a>
regex.icontainsregex<a[^>]*style="[^"]*border:[^"]*"[^>]*>.*?<\/a>
strings.ilikesubstring*fail

Stages and Predicates

Stage 1: mql_rule

and
  not
    any(headers.hops)
      and
        any(headers.hops.fields)
          and
            headers.hops.fields[].name eq "X-Return-Path"
            headers.hops.fields[].value ends_with "docusign.net"
        headers.hops.index eq "0"
  or
    and
      or
        and
          body.html.raw regex_match "<a[^>]*style=\"[^\"]*border:[^\"]*\"[^>]*>.*?<\\/a>"
          body.html.raw regex_match "<a[^>]*style=\"[^\"]*color:\\s*(white|#fff|#ffffff|#FFF|#FFFFFF|rgb\\(\\s*255\\s*,\\s*255\\s*,\\s*255\\s*\\)|rgba\\(\\s*255\\s*,\\s*255\\s*,\\s*255\\s*,\\s*[0-9.]+\\s*\\)|rgb\\(\\s*100%\\s*,\\s*100%\\s*,\\s*100%\\s*\\))[^\"]*\"[^>]*>.*?<\\/a>"
        body.html.raw regex_match "<a[^>]*style=\"[^\"]*background-color:\\s*(#[A-Fa-f0-9]{6}|rgb\\([^)]*\\))[^\"]*\"[^>]*>.*?<span[^>]*>.*?<\\/span>.*?<\\/a>"
      body.html.raw regex_match "<(td|div)[^>]*style=\"[^\"]*background(-color)?:\\s*(#1e4ca1|rgb\\(30,\\s*76,\\s*161\\))[^\"]*\"[^>]*>"
    body.html.raw regex_match "<div[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>|<td[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>"
    body.html.raw regex_match "<table[^>]*cellspacing=\"0\"[^>]*cellpadding=\"0\"[^>]*>\\s*<tbody[^>]*>\\s*<tr[^>]*>\\s*<td[^>]*style=\"BACKGROUND:\\s*rgb\\(247,247,247\\);\\s*width:\\s*[0-9]{2,3}px;\\s*padding:20px;\\s*margin:\\s*[0-9]{2,3}px\"[^>]*>.*<div[^>]*style=\"BACKGROUND:\\s*rgb\\(30,76,161\\);\\s*padding:[0-9]{2,3}px;\\s*color:#EFEFEF\"[^>]*align=\"center\"[^>]*>.*DOCUMENT.*</a>"
    body.html.raw regex_match "background-color:#214e9f;"
    body.html.raw regex_match "background-color:#3260a7"
    body.html.raw regex_match "background-color:\\s*rgb\\(30,\\s*76,\\s*161\\)"
    body.html.raw regex_match "background-color:\\s*rgb\\(61,\\s*170,\\s*73\\)"
    body.html.raw regex_match "background:\\s*rgb\\(30,\\s*76,\\s*161\\)"
  any(body.links)
    and
      or
        body.links.display_text is_null
        body.links.display_text regex_match "\\bDOCUMENT"
      not
        body.links.href_url.domain.root_domain starts_with "docusign."
  or
    and
      any(distinct(headers.hops))
        distinct(headers.hops).authentication_results.dmarc ends_with "fail"
       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
      body.links length_compare "0"
      body.links length_compare "10"
    regex.icount func_call "regex.icount(body.html.raw, \"(<br\\s*/?>[\\s\\n]*)\") > 50"
  or
    any(body.links)
      body.links.display_text regex_match "\\bDOCUMENT"
    any(body.links)
      body.links.display_text regex_match "view.{0,3}doc"
    body.html.raw regex_match "<font size=\"[0-9]\">DocuSign</font>"
    body.html.raw regex_match "<span[^>]*style=\"[^\"]*\">DocuSign<\\/span>"
    body.html.raw regex_match "<strong>DocuSign</strong>"
    body.html.raw regex_match "D&#917540;&#917540;o&#917540;&#917540;c\\x{FE00}uS&#917540;&#917540;i\\x{FE00}gn"
  not
    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"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.hopsarray_any(no value, null check)excludes:headers.hops
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.html.rawregex_match
  • <(td|div)[^>]*style="[^"]*background(-color)?:\s*(#1e4ca1|rgb(30,\s*76,\s*161))[^"]*"[^>]*>
  • <a[^>]*style="[^"]*background-color:\s*(#[A-Fa-f0-9]{6}|rgb([^)]*))[^"]*"[^>]*>.*?<span[^>]*>.*?<\/span>.*?<\/a>
  • <a[^>]*style="[^"]*border:[^"]*"[^>]*>.*?<\/a>
  • <a[^>]*style="[^"]*color:\s*(white|#fff|#ffffff|#FFF|#FFFFFF|rgb(\s*255\s*,\s*255\s*,\s*255\s*)|rgba(\s*255\s*,\s*255\s*,\s*255\s*,\s*[0-9.]+\s*)|rgb(\s*100%\s*,\s*100%\s*,\s*100%\s*))[^"]*"[^>]*>.*?<\/a>
    • <div[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>
    • <td[^>]*BACKGROUND-COLOR: #1e4ca1[^>]*>
  • <font size="[0-9]">DocuSign</font>
  • <span[^>]*style="[^"]*">DocuSign<\/span>
  • <strong>DocuSign</strong>
  • <table[^>]*cellspacing="0"[^>]*cellpadding="0"[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*<td[^>]*style="BACKGROUND:\s*rgb(247,247,247);\s*width:\s*[0-9]{2,3}px;\s*padding:20px;\s*margin:\s*[0-9]{2,3}px"[^>]*>.*<div[^>]*style="BACKGROUND:\s*rgb(30,76,161);\s*padding:[0-9]{2,3}px;\s*color:#EFEFEF"[^>]*align="center"[^>]*>.*DOCUMENT.*</a>
  • D󠀤󠀤o󠀤󠀤c\x{FE00}uS󠀤󠀤i\x{FE00}gn
  • background-color:#214e9f;
  • background-color:#3260a7
  • background-color:\s*rgb(30,\s*76,\s*161)
  • background-color:\s*rgb(61,\s*170,\s*73)
  • background:\s*rgb(30,\s*76,\s*161)
field:"body.html.raw" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Cloud storage impersonation with credential theft indicators

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects messages impersonating cloud storage services that contain hyperlinked images leading to free file hosts, where message screenshots reveal high-confidence credential theft language and storage-related urgency tactics.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree file host, Image as content, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and (
  0 < length(body.current_thread.links) < 10
  or length(body.current_thread.links) > 100
)
and any([subject.subject, sender.display_name],
        regex.icontains(.,
                        "(?:cloud|storage|mailbox|account|system|service|^data)"
        )
)
and any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
        .name == "cred_theft" and .confidence == "high"
)
and not any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,
            .name == "Customer Service and Support" and .confidence == "high"
)
and regex.icontains(beta.ocr(file.message_screenshot()).text,
                    "storage.{0,50}full",
                    "free.{0,50}upgrade",
                    "storage.{0,50}details",
                    "storage.{0,50}quot",
                    "(?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)",
                    '\d{2}%\s*capacity',
                    "data.{0,20}(?:removal|purge|protection mode)",
                    "billing.{0,20}suspended"
)
and not strings.ilike(beta.ocr(file.message_screenshot()).text, "*free plan*")
and (
  any(body.current_thread.links,
      // fingerprints of a hyperlinked image
      .display_text is null
      and .display_url.url is null
      and .href_url.domain.domain not in $tenant_domains
      and (
        .href_url.domain.root_domain in $free_file_hosts
        or .href_url.domain.root_domain in $url_shorteners
        or network.whois(.href_url.domain).days_old < 365
        or .href_url.domain.root_domain == "beehiiv.com"
        or regex.icontains(.href_url.path, '^\/[a-z0-9]{20,}$')
        or (
          strings.icontains(.href_url.path, '.html')
          and coalesce(.href_url.domain.root_domain, "null") != coalesce(sender.email.domain.root_domain,
                                                                         ""
          )
        )
        or "google_adservices" in .href_url.rewrite.encoders
      )
  )
)
// and the sender is not from high trust sender root 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
)

Detection logic

Scope: inbound message.

Detects messages impersonating cloud storage services that contain hyperlinked images leading to free file hosts, where message screenshots reveal high-confidence credential theft language and storage-related urgency tactics.

  1. inbound message
  2. any of:
    • all of:
      • length(body.current_thread.links) > 0
      • length(body.current_thread.links) < 10
    • length(body.current_thread.links) > 100
  3. any of [subject.subject, sender.display_name] where:
    • . matches '(?:cloud|storage|mailbox|account|system|service|^data)'
  4. any of ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents where all hold:
    • .name is 'cred_theft'
    • .confidence is 'high'
  5. not:
    • any of ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics where all hold:
      • .name is 'Customer Service and Support'
      • .confidence is 'high'
  6. beta.ocr(file.message_screenshot()).text matches any of 8 patterns
    • storage.{0,50}full
    • free.{0,50}upgrade
    • storage.{0,50}details
    • storage.{0,50}quot
    • (?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)
    • \d{2}%\s*capacity
    • data.{0,20}(?:removal|purge|protection mode)
    • billing.{0,20}suspended
  7. not:
    • beta.ocr(file.message_screenshot()).text matches '*free plan*'
  8. any of body.current_thread.links where all hold:
    • .display_text is missing
    • .display_url.url is missing
    • .href_url.domain.domain not in $tenant_domains
    • any of:
      • .href_url.domain.root_domain in $free_file_hosts
      • .href_url.domain.root_domain in $url_shorteners
      • network.whois(.href_url.domain).days_old < 365
      • .href_url.domain.root_domain is 'beehiiv.com'
      • .href_url.path matches '^\\/[a-z0-9]{20,}$'
      • all of:
        • .href_url.path contains '.html'
        • coalesce(.href_url.domain.root_domain, 'null') is not coalesce(sender.email.domain.root_domain, '')
      • .href_url.rewrite.encoders contains 'google_adservices'
  9. 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.links[].display_text, body.current_thread.links[].display_url.url, body.current_thread.links[].href_url.domain, body.current_thread.links[].href_url.domain.domain, body.current_thread.links[].href_url.domain.root_domain, body.current_thread.links[].href_url.path, body.current_thread.links[].href_url.rewrite.encoders, headers.auth_summary.dmarc.pass, sender.display_name, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.nlu_classifier, network.whois, regex.icontains, strings.icontains, strings.ilike. Reference lists: $free_file_hosts, $high_trust_sender_root_domains, $tenant_domains, $url_shorteners.

Indicators matched (15)

FieldMatchValue
regex.icontainsregex(?:cloud|storage|mailbox|account|system|service|^data)
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].nameequalscred_theft
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidenceequalshigh
regex.icontainsregexstorage.{0,50}full
regex.icontainsregexfree.{0,50}upgrade
regex.icontainsregexstorage.{0,50}details
regex.icontainsregexstorage.{0,50}quot
regex.icontainsregex(?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)
regex.icontainsregex\d{2}%\s*capacity
regex.icontainsregexdata.{0,20}(?:removal|purge|protection mode)
regex.icontainsregexbilling.{0,20}suspended
body.current_thread.links[].href_url.domain.root_domainequalsbeehiiv.com
3 more
regex.icontainsregex^\/[a-z0-9]{20,}$
strings.icontainssubstring.html
body.current_thread.links[].href_url.rewrite.encoderscontainsgoogle_adservices

Stages and Predicates

Stage 1: mql_rule

and
  any(body.current_thread.links)
    and
      or
        and
          body.current_thread.links.href_url.path contains ".html"
          coalesce func_call "coalesce(body.current_thread.links[].href_url.domain.root_domain, \"null\") != coalesce(sender.email.domain.root_domain, '')"
        body.current_thread.links.href_url.domain.root_domain eq "beehiiv.com"
        body.current_thread.links.href_url.path regex_match "^\\/[a-z0-9]{20,}$"
        body.current_thread.links.href_url.rewrite.encoders contains "google_adservices"
        network.whois func_call "network.whois(body.current_thread.links[].href_url.domain).days_old < 365"
         macro "body.current_thread.links[].href_url.domain.root_domain in free_file_hosts"
         macro "body.current_thread.links[].href_url.domain.root_domain in url_shorteners"
      body.current_thread.links.display_text is_null
      body.current_thread.links.display_url.url is_null
       macro "body.current_thread.links[].href_url.domain.domain not in tenant_domains"
  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"
  not
    any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics)
      and
        ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics.confidence eq "high"
        ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics.name eq "Customer Service and Support"
  or
    and
      body.current_thread.links length_compare "0"
      body.current_thread.links length_compare "10"
    body.current_thread.links length_compare "100"
  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 "cred_theft"
  any([subject.subject, sender.display_name])
    [subject.subject, sender.display_name] regex_match "(?:cloud|storage|mailbox|account|system|service|^data)"
  not
    beta.ocr(file.message_screenshot()).text match "free plan"
  or
    beta.ocr(file.message_screenshot()).text regex_match "(?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)"
    beta.ocr(file.message_screenshot()).text regex_match "\\d{2}%\\s*capacity"
    beta.ocr(file.message_screenshot()).text regex_match "billing.{0,20}suspended"
    beta.ocr(file.message_screenshot()).text regex_match "data.{0,20}(?:removal|purge|protection mode)"
    beta.ocr(file.message_screenshot()).text regex_match "free.{0,50}upgrade"
    beta.ocr(file.message_screenshot()).text regex_match "storage.{0,50}details"
    beta.ocr(file.message_screenshot()).text regex_match "storage.{0,50}full"
    beta.ocr(file.message_screenshot()).text regex_match "storage.{0,50}quot"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topicsarray_any(no value, null check)excludes:ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics
beta.ocr(file.message_screenshot()).textmatchfree planexcludes:beta.ocr(file.message_screenshot()).text field:"beta.ocr(file.message_screenshot()).text" value:"free plan"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textregex_match
  • (?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)
  • \d{2}%\s*capacity
  • billing.{0,20}suspended
  • data.{0,20}(?:removal|purge|protection mode)
  • free.{0,50}upgrade
  • storage.{0,50}details
  • storage.{0,50}full
  • storage.{0,50}quot
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: AWS Lambda URL with recipient targeting

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects messages containing AWS Lambda URLs with the recipient's email address embedded in the fragment, indicating potential abuse of AWS Lambda services for targeted malicious activities.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree subdomain host, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.links
  • recipients
  • recipients.to[0]
  • sender.email
  • type

Rule body

type.inbound
and recipients.to[0].email.domain.sld == sender.email.local_part
and any(body.links,
        strings.icontains(.href_url.domain.domain, "lambda-url")
        and strings.icontains(.href_url.fragment, recipients.to[0].email.email)
)

Detection logic

Scope: inbound message.

Detects messages containing AWS Lambda URLs with the recipient's email address embedded in the fragment, indicating potential abuse of AWS Lambda services for targeted malicious activities.

  1. inbound message
  2. recipients.to[0].email.domain.sld is sender.email.local_part
  3. any of body.links where all hold:
    • .href_url.domain.domain contains 'lambda-url'
    • strings.icontains(.href_url.fragment)

Inspects: body.links, body.links[].href_url.domain.domain, body.links[].href_url.fragment, recipients.to[0].email.domain.sld, recipients.to[0].email.email, sender.email.local_part, type.inbound. Sensors: strings.icontains.

Indicators matched (1)

FieldMatchValue
strings.icontainssubstringlambda-url

Stages and Predicates

Stage 1: mql_rule

and
  any(body.links)
    and
      body.links.href_url.domain.domain contains "lambda-url"
      strings.icontains func_call "strings.icontains(body.links[].href_url.fragment)"
  recipients.to[0].email.domain.sld cross_field_compare "sender.email.local_part"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

Credential phishing: DocuSign embedded image lure with no DocuSign domains in links

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects DocuSign phishing emails with no DocuSign links, a DocuSign logo embedded in the body of the message, from a new sender.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.links
  • headers
  • headers.auth_summary
  • headers.hops
  • sender.email
  • type

Rule body

type.inbound
// link boundary
and length(filter(body.links, .href_url.domain.valid)) < 25

// there are no attachments, or only small, likely signature images
and (
  length(attachments) == 0
  or (
    length(attachments) > 0
    and all(attachments, .size < 8000 and .file_type in $file_types_images)
  )
)

// Screenshot indicates a docusign logo or docusign name with cta to documents
and (
  (
    //
    // 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
    //
    strings.ilike(beta.ocr(file.message_screenshot()).text, "*DocuSign*")
    or any(ml.logo_detect(file.message_screenshot()).brands,
           .name == "DocuSign"
    )
  )
  and (
    (
      (
        //
        // 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
        //
        regex.icontains(beta.ocr(file.message_screenshot()).text,
                        "((re)?view|access|sign|complete(d)?) documen(t)?(s)?",
                        "Your document has been completed",
                        "New Document Shared with you",
                        "Kindly click the link",
                        "important edocs",
                        // German (Document (check|check|sign|sent))
                        "Dokument (überprüfen|prüfen|unterschreiben|geschickt)",
        )
        // German (important|urgent|immediate) but not in the Microsoft link
        or (
          (
            any(body.links,
                .display_text == "Erfahren Sie, warum dies wichtig ist"
                and .href_url.url == "https://aka.ms/LearnAboutSenderIdentification"
            )
            and regex.icount(beta.ocr(file.message_screenshot()).text,
                             "(wichtig|dringend|sofort)"
            ) > 1
          )
          or (
            not any(body.links,
                    .display_text == "Erfahren Sie, warum dies wichtig ist"
                    and .href_url.url == "https://aka.ms/LearnAboutSenderIdentification"
            )
            and regex.icount(beta.ocr(file.message_screenshot()).text,
                             "(wichtig|dringend|sofort)"
            ) > 0
          )
        )
      )
      and any(body.links,
              not strings.ilike(.href_url.domain.root_domain, "docusign.*")
              and (.display_text is null and .display_url.url is null)
      )
    )
    or any(body.links,
           not strings.ilike(.href_url.domain.root_domain, "docusign.*")
           and (
             regex.icontains(strings.replace_confusables(.display_text),
                             '(\bdocument|(view|get your) (docu|file))'
             )
             or strings.icontains(.display_text,
                                  "R\u{200F}E\u{200F}V\u{200F}I\u{200F}E\u{200F}W\u{200F} \u{200F}D\u{200F}O\u{200F}C\u{200F}U\u{200F}M\u{200F}E\u{200F}N\u{200F}T\u{200F}"
             )
           )
    )
  )
)

// links with null display_text that do not go to docusign.* (indicative of hyperlinked image) or the display text contains DOCUMENT
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
)

// negate legit replies
and not (length(headers.references) > 0 or headers.in_reply_to is not null)
and not profile.by_sender().any_messages_benign

// negate docusign X-Return-Path
and not any(headers.hops,
            .index == 0
            and any(.fields,
                    .name == "X-Return-Path"
                    and strings.ends_with(.value, "docusign.net")
            )
)

// negate "via" senders via dmarc authentication
and (
  not coalesce(headers.auth_summary.dmarc.pass
               and strings.contains(sender.display_name, "via")
               and sender.email.domain.domain in $org_domains,
               false
  )
)

Detection logic

Scope: inbound message.

Detects DocuSign phishing emails with no DocuSign links, a DocuSign logo embedded in the body of the message, from a new sender.

  1. inbound message
  2. length(filter(body.links, .href_url.domain.valid)) < 25
  3. any of:
    • length(attachments) is 0
    • all of:
      • length(attachments) > 0
      • all of attachments where all hold:
        • .size < 8000
        • .file_type in $file_types_images
  4. all of:
    • any of:
      • beta.ocr(file.message_screenshot()).text matches '*DocuSign*'
      • any of ml.logo_detect(file.message_screenshot()).brands where:
        • .name is 'DocuSign'
    • any of:
      • all of:
        • any of:
          • beta.ocr(file.message_screenshot()).text matches any of 6 patterns
            • ((re)?view|access|sign|complete(d)?) documen(t)?(s)?
            • Your document has been completed
            • New Document Shared with you
            • Kindly click the link
            • important edocs
            • Dokument (überprüfen|prüfen|unterschreiben|geschickt)
          • any of:
            • all of:
              • any of body.links where all hold:
                • .display_text is 'Erfahren Sie, warum dies wichtig ist'
                • .href_url.url is 'https://aka.ms/LearnAboutSenderIdentification'
              • regex.icount(beta.ocr(file.message_screenshot()).text, '(wichtig|dringend|sofort)') > 1
            • all of:
              • not:
                • any of body.links where all hold:
                  • .display_text is 'Erfahren Sie, warum dies wichtig ist'
                  • .href_url.url is 'https://aka.ms/LearnAboutSenderIdentification'
              • regex.icount(beta.ocr(file.message_screenshot()).text, '(wichtig|dringend|sofort)') > 0
        • any of body.links where all hold:
          • not:
            • .href_url.domain.root_domain matches 'docusign.*'
          • all of:
            • .display_text is missing
            • .display_url.url is missing
      • any of body.links where all hold:
        • not:
          • .href_url.domain.root_domain matches 'docusign.*'
        • any of:
          • strings.replace_confusables(.display_text) matches '(\\bdocument|(view|get your) (docu|file))'
          • .display_text contains 'R\\u{200F}E\\u{200F}V\\u{200F}I\\u{200F}E\\u{200F}W\\u{200F} \\u{200F}D\\u{200F}O\\u{200F}C\\u{200F}U\\u{200F}M\\u{200F}E\\u{200F}N\\u{200F}T\\u{200F}'
  5. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  6. 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
  7. none of:
    • length(headers.references) > 0
    • headers.in_reply_to is set
  8. not:
    • profile.by_sender().any_messages_benign
  9. not:
    • any of headers.hops where all hold:
      • .index is 0
      • any of .fields where all hold:
        • .name is 'X-Return-Path'
        • .value ends with 'docusign.net'
  10. not:
    • coalesce(headers.auth_summary.dmarc.pass and strings.contains(sender.display_name, 'via') and sender.email.domain.domain in $org_domains)

Inspects: attachments[].file_type, attachments[].size, body.links, body.links[].display_text, body.links[].display_url.url, body.links[].href_url.domain.root_domain, body.links[].href_url.domain.valid, body.links[].href_url.url, headers.auth_summary.dmarc.pass, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, headers.hops[].index, headers.in_reply_to, headers.references, sender.display_name, sender.email.domain.domain, sender.email.domain.root_domain, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.logo_detect, profile.by_sender, regex.icontains, regex.icount, strings.contains, strings.ends_with, strings.icontains, strings.ilike, strings.replace_confusables. Reference lists: $file_types_images, $high_trust_sender_root_domains, $org_domains.

Indicators matched (13)

FieldMatchValue
strings.ilikesubstring*DocuSign*
ml.logo_detect(file.message_screenshot()).brands[].nameequalsDocuSign
regex.icontainsregex((re)?view|access|sign|complete(d)?) documen(t)?(s)?
regex.icontainsregexYour document has been completed
regex.icontainsregexNew Document Shared with you
regex.icontainsregexKindly click the link
regex.icontainsregeximportant edocs
regex.icontainsregexDokument (überprüfen|prüfen|unterschreiben|geschickt)
body.links[].display_textequalsErfahren Sie, warum dies wichtig ist
body.links[].href_url.urlequalshttps://aka.ms/LearnAboutSenderIdentification
regex.icountregex(wichtig|dringend|sofort)
regex.icontainsregex(\bdocument|(view|get your) (docu|file))
1 more
strings.icontainssubstringR\u{200F}E\u{200F}V\u{200F}I\u{200F}E\u{200F}W\u{200F} \u{200F}D\u{200F}O\u{200F}C\u{200F}U\u{200F}M\u{200F}E\u{200F}N\u{200F}T\u{200F}

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        and
          not
            any(body.links)
              and
                body.links.display_text eq "Erfahren Sie, warum dies wichtig ist"
                body.links.href_url.url eq "https://aka.ms/LearnAboutSenderIdentification"
          regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(wichtig|dringend|sofort)\") > 0"
        and
          any(body.links)
            and
              body.links.display_text eq "Erfahren Sie, warum dies wichtig ist"
              body.links.href_url.url eq "https://aka.ms/LearnAboutSenderIdentification"
          regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(wichtig|dringend|sofort)\") > 1"
        beta.ocr(file.message_screenshot()).text regex_match "((re)?view|access|sign|complete(d)?) documen(t)?(s)?"
        beta.ocr(file.message_screenshot()).text regex_match "Dokument (überprüfen|prüfen|unterschreiben|geschickt)"
        beta.ocr(file.message_screenshot()).text regex_match "Kindly click the link"
        beta.ocr(file.message_screenshot()).text regex_match "New Document Shared with you"
        beta.ocr(file.message_screenshot()).text regex_match "Your document has been completed"
        beta.ocr(file.message_screenshot()).text regex_match "important edocs"
      any(body.links)
        and
          not
            body.links.href_url.domain.root_domain starts_with "docusign."
          body.links.display_text is_null
          body.links.display_url.url is_null
    any(body.links)
      and
        or
          body.links.display_text contains "R\\u{200F}E\\u{200F}V\\u{200F}I\\u{200F}E\\u{200F}W\\u{200F} \\u{200F}D\\u{200F}O\\u{200F}C\\u{200F}U\\u{200F}M\\u{200F}E\\u{200F}N\\u{200F}T\\u{200F}"
          strings.replace_confusables(body.links[].display_text) regex_match "(\\bdocument|(view|get your) (docu|file))"
        not
          body.links.href_url.domain.root_domain starts_with "docusign."
  not
    any(headers.hops)
      and
        any(headers.hops.fields)
          and
            headers.hops.fields[].name eq "X-Return-Path"
            headers.hops.fields[].value ends_with "docusign.net"
        headers.hops.index eq "0"
  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
    and
      attachments length_compare "0"
       macro "all(attachments)"
    attachments length_compare "0"
  not
    or
      headers.in_reply_to is_not_null
      headers.references length_compare "0"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name eq "DocuSign"
    beta.ocr(file.message_screenshot()).text match "DocuSign"
  not
    coalesce func_call "coalesce(headers.auth_summary.dmarc.pass and strings.contains(sender.display_name, 'via') and sender.email.domain.domain in $org_domains)"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  filter(body.links, .href_url.domain.valid) length_compare "25"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.hopsarray_any(no value, null check)excludes:headers.hops
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textregex_match
  • ((re)?view|access|sign|complete(d)?) documen(t)?(s)?
  • Dokument (überprüfen|prüfen|unterschreiben|geschickt)
  • Kindly click the link
  • New Document Shared with you
  • Your document has been completed
  • important edocs
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
beta.ocr(file.message_screenshot()).textwildcard
  • *DocuSign*
field:"beta.ocr(file.message_screenshot()).text" kind:wildcard value:"*DocuSign*"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Email delivery failure impersonation

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects phishing emails impersonating email system notifications claiming delivery failures, rejected messages, or email system issues requiring user action to 'fix' or 'recover' email functionality. These attacks typically claim incoming emails couldn't be delivered and direct users to malicious portals to harvest credentials.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • headers.domains
  • recipients
  • recipients.to
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(body.links) < 10
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name == "cred_theft" and .confidence == "high"
  )
  or (
    length(body.current_thread.text) < 250
    and any(recipients.to,
            strings.icontains(body.current_thread.text, .email.domain.sld)
            or strings.icontains(body.current_thread.text, .email.local_part)
    )
  )
)
and (
  regex.icontains(subject.subject, '(e)?mail(s)?')
  or (
    length(body.current_thread.text) < 700
    and strings.ilike(body.current_thread.text, '*mail*')
  )
)
and 3 of (
  strings.ilike(body.current_thread.text, "*incoming messages*"),
  strings.ilike(body.current_thread.text, "*server error*"),
  strings.ilike(body.current_thread.text, "*blocked*"),
  strings.ilike(body.current_thread.text, "*prevented*"),
  strings.ilike(body.current_thread.text, "*notification*"),
  strings.ilike(body.current_thread.text, "*fix email issues*"),
  strings.ilike(body.current_thread.text, "*rejected*"),
  strings.ilike(body.current_thread.text, "*recover and prevent*"),
  strings.ilike(body.current_thread.text, "*failure*"),
  strings.ilike(body.current_thread.text, "*rejection*"),
  strings.ilike(body.current_thread.text, "*failed*")
)
and (
  any(body.links,
      regex.icontains(.display_text,
                      "view",
                      "messages",
                      "recover",
                      "fix",
                      "portal",
                      "connect"
      )
      and not .display_text == "View Report"
      and .href_url.domain.root_domain in ("gmass.co")
  )
  or (
    length(body.links) < 3
    and any(body.links,
            any(recipients.to,
                .email.domain.root_domain == ..display_url.domain.root_domain
                and ..mismatched
            )
    )
  )
  or (all(recipients.to, .email.local_part == sender.display_name))
  or any(body.links,
         any(.href_url.rewrite.encoders, . == "proofpoint")
         and .href_url.domain.root_domain not in $tranco_50k
         and .href_url.domain.root_domain not in $org_domains
  )
)
and not any(body.links,
            regex.icontains(.display_text,
                            "view document",
                            "review (&|and) sign document"
            )
)
and sender.email.domain.root_domain not in (
  "bing.com",
  "microsoft.com",
  "microsoftonline.com",
  "microsoftsupport.com",
  "microsoft365.com",
  "office.com",
  "office365.com",
  "onedrive.com",
  "sharepointonline.com",
  "yammer.com",
  "ppops.net"
)

// negate org domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $org_domains
    and (
      not headers.auth_summary.dmarc.pass
      // MS  emails from an org domain are router "internally" to MS, therefore, there is no authentication information
      or not (
        headers.auth_summary.dmarc.pass is null
        and all(headers.domains,
                .root_domain in ("outlook.com", "office365.com")
        )
        // typical emails from freemail Outlook accounts are from prod.outlook.com
        and strings.ends_with(headers.message_id, "protection.outlook.com>")
      )
    )
  )
  or sender.email.domain.root_domain not in $org_domains
)

// 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 not profile.by_sender().solicited
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

Detects phishing emails impersonating email system notifications claiming delivery failures, rejected messages, or email system issues requiring user action to 'fix' or 'recover' email functionality. These attacks typically claim incoming emails couldn't be delivered and direct users to malicious portals to harvest credentials.

  1. inbound message
  2. length(body.links) < 10
  3. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'cred_theft'
      • .confidence is 'high'
    • all of:
      • length(body.current_thread.text) < 250
      • any of recipients.to where any holds:
        • strings.icontains(body.current_thread.text)
        • strings.icontains(body.current_thread.text)
  4. any of:
    • subject.subject matches '(e)?mail(s)?'
    • all of:
      • length(body.current_thread.text) < 700
      • body.current_thread.text matches '*mail*'
  5. at least 3 of 11: body.current_thread.text matches any of 11 patterns
    • *incoming messages*
    • *server error*
    • *blocked*
    • *prevented*
    • *notification*
    • *fix email issues*
    • *rejected*
    • *recover and prevent*
    • *failure*
    • *rejection*
    • *failed*
  6. any of:
    • any of body.links where all hold:
      • .display_text matches any of 6 patterns
        • view
        • messages
        • recover
        • fix
        • portal
        • connect
      • not:
        • .display_text is 'View Report'
      • .href_url.domain.root_domain in ('gmass.co')
    • all of:
      • length(body.links) < 3
      • any of body.links where:
        • any of recipients.to where all hold:
          • .email.domain.root_domain is .display_url.domain.root_domain
          • .mismatched
    • all of recipients.to where:
      • .email.local_part is sender.display_name
    • any of body.links where all hold:
      • any of .href_url.rewrite.encoders where:
        • . is 'proofpoint'
      • .href_url.domain.root_domain not in $tranco_50k
      • .href_url.domain.root_domain not in $org_domains
  7. not:
    • any of body.links where:
      • .display_text matches any of 2 patterns
        • view document
        • review (&|and) sign document
  8. sender.email.domain.root_domain not in ('bing.com', 'microsoft.com', 'microsoftonline.com', 'microsoftsupport.com', 'microsoft365.com', 'office.com', 'office365.com', 'onedrive.com', 'sharepointonline.com', 'yammer.com', 'ppops.net')
  9. any of:
    • all of:
      • sender.email.domain.root_domain in $org_domains
      • any of:
        • not:
          • headers.auth_summary.dmarc.pass
        • not:
          • all of:
            • headers.auth_summary.dmarc.pass is missing
            • all of headers.domains where:
              • .root_domain in ('outlook.com', 'office365.com')
            • headers.message_id ends with 'protection.outlook.com>'
    • sender.email.domain.root_domain not in $org_domains
  10. 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
  11. not:
    • profile.by_sender().solicited
  12. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].display_url.domain.root_domain, body.links[].href_url.domain.root_domain, body.links[].href_url.rewrite.encoders, body.links[].mismatched, headers.auth_summary.dmarc.pass, headers.domains, headers.domains[].root_domain, headers.message_id, recipients.to, recipients.to[].email.domain.root_domain, recipients.to[].email.domain.sld, recipients.to[].email.local_part, sender.display_name, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, strings.ends_with, strings.icontains, strings.ilike. Reference lists: $high_trust_sender_root_domains, $org_domains, $tranco_50k.

Indicators matched (23)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh
regex.icontainsregex(e)?mail(s)?
strings.ilikesubstring*mail*
strings.ilikesubstring*incoming messages*
strings.ilikesubstring*server error*
strings.ilikesubstring*blocked*
strings.ilikesubstring*prevented*
strings.ilikesubstring*notification*
strings.ilikesubstring*fix email issues*
strings.ilikesubstring*rejected*
strings.ilikesubstring*recover and prevent*
11 more
strings.ilikesubstring*failure*
strings.ilikesubstring*rejection*
strings.ilikesubstring*failed*
regex.icontainsregexview
regex.icontainsregexmessages
regex.icontainsregexrecover
regex.icontainsregexfix
regex.icontainsregexportal
regex.icontainsregexconnect
body.links[].href_url.domain.root_domainmembergmass.co
body.links[].href_url.rewrite.encoders[]equalsproofpoint

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(body.links)
        any(recipients.to)
          and
            body.links.mismatched eq "true"
            recipients.to.email.domain.root_domain cross_field_compare "body.links.display_url.domain.root_domain"
      body.links length_compare "3"
    any(body.links)
      and
        not
          body.links.display_text eq "View Report"
        or
          body.links.display_text regex_match "connect"
          body.links.display_text regex_match "fix"
          body.links.display_text regex_match "messages"
          body.links.display_text regex_match "portal"
          body.links.display_text regex_match "recover"
          body.links.display_text regex_match "view"
        body.links.href_url.domain.root_domain eq "gmass.co"
    any(body.links)
      and
        any(body.links.href_url.rewrite.encoders)
          body.links.href_url.rewrite.encoders eq "proofpoint"
         macro "body.links[].href_url.domain.root_domain not in org_domains"
         macro "body.links[].href_url.domain.root_domain not in tranco_50k"
     macro "all(recipients.to)"
  or
    and
      or
        not
          and
            headers.auth_summary.dmarc.pass is_null
            headers.message_id ends_with "protection.outlook.com>"
             macro "all(headers.domains)"
        not
          headers.auth_summary.dmarc.pass eq "true"
       macro "sender.email.domain.root_domain in org_domains"
     macro "sender.email.domain.root_domain not in org_domains"
  not
    any(body.links)
      or
        body.links.display_text regex_match "review (&|and) sign document"
        body.links.display_text regex_match "view document"
  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).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
    and
      any(recipients.to)
        strings.icontains func_call "strings.icontains(body.current_thread.text)"
      body.current_thread.text length_compare "250"
  or
    and
      body.current_thread.text length_compare "700"
      body.current_thread.text match "mail"
    subject.subject regex_match "(e)?mail(s)?"
  or
    body.current_thread.text match "blocked"
    body.current_thread.text match "failed"
    body.current_thread.text match "failure"
    body.current_thread.text match "fix email issues"
    body.current_thread.text match "incoming messages"
    body.current_thread.text match "notification"
    body.current_thread.text match "prevented"
    body.current_thread.text match "recover and prevent"
    body.current_thread.text match "rejected"
    body.current_thread.text match "rejection"
    body.current_thread.text match "server error"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  not
    profile.by_sender func_call "profile.by_sender().solicited"
  not
    sender.email.domain.root_domain in ["bing.com", "microsoft.com", "microsoft365.com", "microsoftonline.com", "microsoftsupport.com", "office.com", "office365.com", "onedrive.com", "ppops.net", "sharepointonline.com", "yammer.com"]
  body.links length_compare "10"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
body.linksarray_any(no value, null check)excludes:body.links
sender.email.domain.root_domaininbing.com, microsoft.com, microsoft365.com, microsoftonline.com, microsoftsupport.com, office.com, office365.com, onedrive.com, ppops.net, sharepointonline.com, yammer.comexcludes:sender.email.domain.root_domain

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • *blocked*
  • *failed*
  • *failure*
  • *fix email issues*
  • *incoming messages*
  • *mail*
  • *notification*
  • *prevented*
  • *recover and prevent*
  • *rejected*
  • *rejection*
  • *server error*
field:"body.current_thread.text" kind:wildcard
subject.subjectregex_match
  • (e)?mail(s)?
field:"subject.subject" kind:regex_match value:"(e)?mail(s)?"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Fake card notification with tracking lure

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects inbound messages using fake credit card delivery or approval themes with credential theft intent. Messages contain card-related language paired with delivery or status indicators, and tracking call-to-action links.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and (
  (
    regex.icontains(subject.base, '\bcard\b')
    or regex.icontains(body.current_thread.text, '\bcard\b')
  )
  and strings.ilike(body.current_thread.text,
                    "*could be with you*",
                    "*currently accessible*",
                    "*collect bank details*",
                    "*not a financial institution*"
  )
)
and any(body.links,
        strings.ilike(.display_text,
                      "*track order*",
                      "*track*card*",
                      "*card status*"
        )
)
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name == "cred_theft" and .confidence == "high"
)
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 using fake credit card delivery or approval themes with credential theft intent. Messages contain card-related language paired with delivery or status indicators, and tracking call-to-action links.

  1. inbound message
  2. all of:
    • any of:
      • subject.base matches '\\bcard\\b'
      • body.current_thread.text matches '\\bcard\\b'
    • body.current_thread.text matches any of 4 patterns
      • *could be with you*
      • *currently accessible*
      • *collect bank details*
      • *not a financial institution*
  3. any of body.links where:
    • .display_text matches any of 3 patterns
      • *track order*
      • *track*card*
      • *card status*
  4. any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
    • .name is 'cred_theft'
    • .confidence is 'high'
  5. 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, body.links, body.links[].display_text, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, subject.base, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.ilike. Reference lists: $high_trust_sender_root_domains.

Indicators matched (10)

FieldMatchValue
regex.icontainsregex\bcard\b
strings.ilikesubstring*could be with you*
strings.ilikesubstring*currently accessible*
strings.ilikesubstring*collect bank details*
strings.ilikesubstring*not a financial institution*
strings.ilikesubstring*track order*
strings.ilikesubstring*track*card*
strings.ilikesubstring*card status*
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh

Stages and Predicates

Stage 1: mql_rule

and
  any(body.links)
    or
      body.links.display_text match "card status"
      body.links.display_text match "track order"
      body.links.display_text wildcard "*track*card*"
  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).intents)
    and
      ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
      ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
  or
    body.current_thread.text match "collect bank details"
    body.current_thread.text match "could be with you"
    body.current_thread.text match "currently accessible"
    body.current_thread.text match "not a financial institution"
  or
    body.current_thread.text regex_match "\\bcard\\b"
    subject.base regex_match "\\bcard\\b"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

Credential phishing: Financial lure via ActiveCampaign infrastructure

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects inbound phishing messages sent via ActiveCampaign using identifiable infrastructure fingerprints and hidden boilerplate text. Covers a wide range of lure themes including credit cards, loans, deposits, account updates, and vague document or verification prompts. Requires NLU Financial Communications topic classification.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and strings.contains(headers.mailer, "ActiveCampaign")
and (
  strings.ilike(body.html.inner_text,
                "*Piratini*",
                "*45.405.898/0001-16*",
                "*Cancelar inscri*",
                "*Matem?tica Genial*"
  )
  or strings.ilike(body.html.raw,
                   "*belonging to Spun*",
                   "*affiliated with Spun*"
  )
)
and (
  length(html.xpath(body.html,
                    '//*[contains(@style, "background") and contains(@style, "padding")] | //a[contains(@class, "es-button")]'
         ).nodes
  ) > 0
  or length(html.xpath(body.html, '//a/img').nodes) > 0
)
and ml.nlu_classifier(body.current_thread.text).language == "english"
and not any(ml.nlu_classifier(body.current_thread.text).topics,
            .name in ("Health and Wellness", "Entertainment and Sports")
            and .confidence == "high"
)
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 phishing messages sent via ActiveCampaign using identifiable infrastructure fingerprints and hidden boilerplate text. Covers a wide range of lure themes including credit cards, loans, deposits, account updates, and vague document or verification prompts. Requires NLU Financial Communications topic classification.

  1. inbound message
  2. headers.mailer contains 'ActiveCampaign'
  3. any of:
    • body.html.inner_text matches any of 4 patterns
      • *Piratini*
      • *45.405.898/0001-16*
      • *Cancelar inscri*
      • *Matem?tica Genial*
    • body.html.raw matches any of 2 patterns
      • *belonging to Spun*
      • *affiliated with Spun*
  4. any of:
    • length(html.xpath(body.html, '//*[contains(@style, "background") and contains(@style, "padding")] | //a[contains(@class, "es-button")]').nodes) > 0
    • length(html.xpath(body.html, '//a/img').nodes) > 0
  5. ml.nlu_classifier(body.current_thread.text).language is 'english'
  6. not:
    • any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
      • .name in ('Health and Wellness', 'Entertainment and Sports')
      • .confidence is 'high'
  7. 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, body.html, body.html.inner_text, body.html.raw, headers.auth_summary.dmarc.pass, headers.mailer, sender.email.domain.root_domain, type.inbound. Sensors: html.xpath, ml.nlu_classifier, strings.contains, strings.ilike. Reference lists: $high_trust_sender_root_domains.

Indicators matched (7)

FieldMatchValue
strings.containssubstringActiveCampaign
strings.ilikesubstring*Piratini*
strings.ilikesubstring*45.405.898/0001-16*
strings.ilikesubstring*Cancelar inscri*
strings.ilikesubstring*Matem?tica Genial*
strings.ilikesubstring*belonging to Spun*
strings.ilikesubstring*affiliated with Spun*

Stages and Predicates

Stage 1: mql_rule

and
  not
    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 ["Entertainment and Sports", "Health and Wellness"]
  not
    and
      coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  or
    body.html.inner_text match "45.405.898/0001-16"
    body.html.inner_text match "Cancelar inscri"
    body.html.inner_text match "Matem?tica Genial"
    body.html.inner_text match "Piratini"
    body.html.raw match "affiliated with Spun"
    body.html.raw match "belonging to Spun"
  or
    html.xpath(body.html, '//*[contains(@style, "background") and contains(@style, "padding")] | //a[contains(@class, "es-button")]').nodes length_compare "0"
    html.xpath(body.html, '//a/img').nodes length_compare "0"
  headers.mailer contains "ActiveCampaign"
  ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language == english"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ml.nlu_classifier(body.current_thread.text).topicsarray_any(no value, null check)excludes:ml.nlu_classifier(body.current_thread.text).topics

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.html.inner_textwildcard
  • *45.405.898/0001-16*
  • *Cancelar inscri*
  • *Matem?tica Genial*
  • *Piratini*
field:"body.html.inner_text" kind:wildcard
body.html.rawwildcard
  • *affiliated with Spun*
  • *belonging to Spun*
field:"body.html.raw" kind:wildcard
headers.mailercontains
  • ActiveCampaign
field:"headers.mailer" kind:contains value:"ActiveCampaign"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Generic document share with unicode and proceedural greeting template

#
Severity
low
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesBEC/Fraud, Credential Phishing
Tactics and techniquesSocial engineering, Evasion

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • mailbox
  • recipients
  • recipients.bcc
  • recipients.to
  • recipients.to[0]
  • sender.email
  • subject
  • type

Rule body

type.inbound
and (
  // nlu capture for wide scope of greetings to reduce evasion
  any(filter(ml.nlu_classifier(body.current_thread.text).entities,
             .name == "greeting"
      ),
      any([
            recipients.to[0].email.domain.sld,
            recipients.to[0].email.local_part,
            recipients.to[0].email.domain.domain,
            // "firstlast" naming convention observed
            strings.concat(mailbox.first_name, mailbox.last_name)
          ],
          // recipient entity follows the greeting in the body text
          strings.icontains(body.current_thread.text,
                            strings.concat(..text, " ", .)
          )
      )
  )
  or (
    // nlu capture for wide scope of greetings to reduce evasion
    any(filter(ml.nlu_classifier(body.current_thread.text).entities,
               .name == "greeting"
        ),
        // nlu capture for wide scope of recipient entity to reduce evasion
        any(filter(ml.nlu_classifier(body.current_thread.text).entities,
                   .name == "recipient"
                   and not (
                     strings.icontains(.text, "customer")
                     // accounting for grouped recipients
                     or regex.icontains(.text, '&|\band\b')
                   )
            ),
            // recipient entity follows the greeting in the body text
            strings.icontains(body.current_thread.text,
                              strings.concat(..text, " ", .text)
            )
            // the named recipient doesn't match the actual "to" recipient
            and not any([
                          recipients.to[0].email.domain.sld,
                          recipients.to[0].email.local_part,
                          recipients.to[0].email.domain.domain,
                          mailbox.first_name,
                        ],
                        strings.icontains(..text, .)
            )
        )
    )
  )
  or any([
           recipients.to[0].email.domain.sld,
           recipients.to[0].email.local_part,
           recipients.to[0].email.domain.domain,
           // "firstlast" naming convention observed
           strings.concat(mailbox.first_name, mailbox.last_name)
         ],
         // strings logic for non-greeting body starter
         strings.icontains(body.current_thread.text,
                           strings.concat("attn: ", .)
         )
         // strings logic for recipient as body starter
         or strings.icontains(body.current_thread.text,
                              strings.concat(., " balance statement")
         )
  )
  // count of all recipient elements is 2 or greater
  or length(filter([
                     recipients.to[0].email.domain.sld,
                     recipients.to[0].email.local_part,
                     recipients.to[0].email.domain.domain,
                     // "firstlast" naming convention observed
                     strings.concat(mailbox.first_name, mailbox.last_name)
                   ],
                   strings.icontains(body.current_thread.text, .)
            )
  ) >= 2

  // logic for broken attack
  or any(ml.nlu_classifier(body.current_thread.text).entities,
         .name == "recipient" and regex.icontains(.text, '[{}]')
  )
)

// unicode + keyword generic template
and (
  (
    (
      regex.icontains(body.current_thread.text,
                      '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)',
                      '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
      )
      // negate sharepoint paths with unicode
      and not any(body.links,
                  regex.icontains(.display_url.path,
                                  '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
                  )
      )
    )
    // start of body is unicode & CTA button is present
    or (
      regex.icontains(body.current_thread.text,
                      '^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
      )
      and any(body.links,
              regex.icontains(.display_text,
                              '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)'
              )
      )
    )
  )
)

// strings negations
and not regex.icontains(body.current_thread.text,
                        'meeting (?:note|recap)|daily brief|brief recap'
)

// nlu intent negation for FP's
and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")

// nlu topic negations
and not any(ml.nlu_classifier(body.current_thread.text).topics,
            .name in ("Software and App Updates", "B2B Cold Outreach")
)

// negate multiple recipients unless undisclosed recipients
and not (
  length(recipients.to) == 1
  and (
    (length(recipients.cc) != 0 or length(recipients.bcc) != 0)
    // notification automation
    and not any(recipients.bcc, .email.local_part == "notifications")
  )
  and not (
    length(recipients.to) == 0
    or all(recipients.to, .email.domain.valid == false)
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and not coalesce(headers.auth_summary.dmarc.pass, false)
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

// negate legitimate conversations
and not (
  (length(headers.references) > 0 or headers.in_reply_to is not null)
  and (subject.is_forward or subject.is_reply)
  and length(body.previous_threads) >= 1
)

// sender negations
and not (
  sender.email.domain.root_domain in (
    "gc.ai",
    "getguru.com",
    "glean.com",
    "mentorloop.com",
  )
  and coalesce(headers.auth_summary.dmarc.pass, false)
)

Detection logic

Scope: inbound message.

Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible.

  1. inbound message
  2. any of:
    • any of filter(...) where:
      • any of [recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name)] where:
        • strings.icontains(body.current_thread.text)
    • any of filter(...) where:
      • any of filter(...) where all hold:
        • strings.icontains(body.current_thread.text)
        • not:
          • any of [recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, mailbox.first_name] where:
            • strings.icontains(.text)
    • any of [recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name)] where any holds:
      • strings.icontains(body.current_thread.text)
      • strings.icontains(body.current_thread.text)
    • length(filter([recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name, mailbox.last_name)], strings.icontains(body.current_thread.text, .))) ≥ 2
    • any of ml.nlu_classifier(body.current_thread.text).entities where all hold:
      • .name is 'recipient'
      • .text matches '[{}]'
  3. any of:
    • all of:
      • body.current_thread.text matches any of 2 patterns
        • (?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)
        • (?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})
      • not:
        • any of body.links where:
          • .display_url.path matches '(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})'
    • all of:
      • body.current_thread.text matches '^(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})'
      • any of body.links where:
        • .display_text matches '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\\bmail\\b)'
  4. not:
    • body.current_thread.text matches 'meeting (?:note|recap)|daily brief|brief recap'
  5. any of ml.nlu_classifier(body.current_thread.text).intents where:
    • .name is not 'benign'
  6. not:
    • any of ml.nlu_classifier(body.current_thread.text).topics where:
      • .name in ('Software and App Updates', 'B2B Cold Outreach')
  7. not:
    • all of:
      • length(recipients.to) is 1
      • all of:
        • any of:
          • length(recipients.cc) is not 0
          • length(recipients.bcc) is not 0
        • not:
          • any of recipients.bcc where:
            • .email.local_part is 'notifications'
      • none of:
        • length(recipients.to) is 0
        • all of recipients.to where:
          • .email.domain.valid is False
  8. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • not:
        • coalesce(headers.auth_summary.dmarc.pass)
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains
  9. not:
    • all of:
      • any of:
        • length(headers.references) > 0
        • headers.in_reply_to is set
      • any of:
        • subject.is_forward
        • subject.is_reply
      • length(body.previous_threads) ≥ 1
  10. not:
    • all of:
      • sender.email.domain.root_domain in ('gc.ai', 'getguru.com', 'glean.com', 'mentorloop.com')
      • coalesce(headers.auth_summary.dmarc.pass)

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].display_url.path, body.previous_threads, headers.auth_summary.dmarc.pass, headers.in_reply_to, headers.references, mailbox.first_name, mailbox.last_name, recipients.bcc, recipients.bcc[].email.local_part, recipients.cc, recipients.to, recipients.to[0].email.domain.domain, recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[].email.domain.valid, sender.email.domain.root_domain, subject.is_forward, subject.is_reply, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.concat, strings.icontains. Reference lists: $high_trust_sender_root_domains.

Indicators matched (8)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsgreeting
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsrecipient
regex.icontainsregex[{}]
regex.icontainsregex(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)
regex.icontainsregex(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})
regex.icontainsregex^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})
regex.icontainsregex(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)
recipients.bcc[].email.local_partequalsnotifications

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(filter(...))
      any(filter(...))
        and
          not
            any([recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, mailbox.first_name])
              strings.icontains func_call "strings.icontains(filter(...)[].text)"
          strings.icontains func_call "strings.icontains(body.current_thread.text)"
    any(ml.nlu_classifier(body.current_thread.text).entities)
      and
        ml.nlu_classifier(body.current_thread.text).entities.name eq "recipient"
        ml.nlu_classifier(body.current_thread.text).entities.text regex_match "[{}]"
    any(filter(...))
      any([recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name)])
        strings.icontains func_call "strings.icontains(body.current_thread.text)"
    any([recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name)])
      strings.icontains func_call "strings.icontains(body.current_thread.text)"
    filter([recipients.to[0].email.domain.sld, recipients.to[0].email.local_part, recipients.to[0].email.domain.domain, strings.concat(mailbox.first_name, mailbox.last_name)], strings.icontains(body.current_thread.text, .)) length_compare "2"
  or
    and
      not
        any(body.links)
          body.links.display_url.path regex_match "(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})"
      or
        body.current_thread.text regex_match "(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})\\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\\bmail\\b)"
        body.current_thread.text regex_match "(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\\bmail\\b)\\n?.{0,15}(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})"
    and
      any(body.links)
        body.links.display_text regex_match "(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\\bmail\\b)"
      body.current_thread.text regex_match "^(?:\\x{2710}|\\x{270D}|\\x{270E}|\\x{270F}|\\x{1F4C1}|\\x{1F4C4}|\\x{1F4D1}|\\x{1F4DD})"
  not
    and
      not
        any(recipients.bcc)
          recipients.bcc.email.local_part eq "notifications"
      not
        or
          recipients.to length_compare "0"
           macro "all(recipients.to)"
      or
        recipients.bcc length_compare "0"
        recipients.cc length_compare "0"
      recipients.to length_compare "1"
  or
    and
      not
        coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
       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"
  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 "1"
  not
    and
      coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
      sender.email.domain.root_domain in ["gc.ai", "getguru.com", "glean.com", "mentorloop.com"]
  not
    any(ml.nlu_classifier(body.current_thread.text).topics)
      ml.nlu_classifier(body.current_thread.text).topics.name in ["B2B Cold Outreach", "Software and App Updates"]
  not
    body.current_thread.text regex_match "meeting (?:note|recap)|daily brief|brief recap"
  any(ml.nlu_classifier(body.current_thread.text).intents)
    ml.nlu_classifier(body.current_thread.text).intents.name ne "benign"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
recipients.bccarray_any(no value, null check)excludes:recipients.bcc
recipients.tolength_compare0excludes:recipients.to field:"recipients.to" value:"0"
recipients.bcclength_compare0excludes:recipients.bcc field:"recipients.bcc" value:"0"
recipients.cclength_compare0excludes:recipients.cc field:"recipients.cc" value:"0"
recipients.tolength_compare1excludes:recipients.to field:"recipients.to" value:"1"
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"
subject.is_forwardeqtrueexcludes:subject.is_forward field:"subject.is_forward" value:"true"
subject.is_replyeqtrueexcludes:subject.is_reply field:"subject.is_reply" value:"true"
body.previous_threadslength_compare1excludes:body.previous_threads field:"body.previous_threads" value:"1"
sender.email.domain.root_domainingc.ai, getguru.com, glean.com, mentorloop.comexcludes:sender.email.domain.root_domain
ml.nlu_classifier(body.current_thread.text).topicsarray_any(no value, null check)excludes:ml.nlu_classifier(body.current_thread.text).topics
body.current_thread.textregex_matchmeeting (?:note|recap), daily brief, brief recapexcludes:body.current_thread.text field:"body.current_thread.text" value:"meeting (?:note|recap)" field:"body.current_thread.text" value:"daily brief" field:"body.current_thread.text" value:"brief recap"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • (?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)
  • (?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})
  • ^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})
field:"body.current_thread.text" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Generic document sharing

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects credential phishing attempts using generic document sharing language where the sender claims to have sent a document for review, but the link doesn't point to legitimate file sharing services.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing, BEC/Fraud
Tactics and techniquesSocial engineering, Evasion, Impersonation: Employee

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • recipients
  • recipients.to
  • recipients.to[0]
  • sender.email
  • subject
  • type

Rule body

type.inbound
// exclude if it's a reply to an existing conversation
and (
  not length(body.previous_threads) > 0
  // still match if self-sender BCC pattern
  or (
    length(recipients.to) == 1
    and length(recipients.cc) == 0
    and sender.email.email == recipients.to[0].email.email
  )
)
and (
  // subject contains document sharing language
  regex.icontains(subject.base,
                  '\b(has\s+sent\s+you|sent\s+you|shared\s+with\s+you|document\s+to\s+review|document\s*(number|num|#)|file\s+to\s+review|proposal\s+(?:document|submission)|new\s+document|document\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b'
  )
  or strings.icontains(subject.subject, 'document to review')
  or strings.icontains(subject.subject, 'file to review')
  or strings.icontains(subject.subject, 'sent you')
  or strings.icontains(subject.subject, 'eDocuments Notification')
  // or recipient's SLD is the subject
  or (
    subject.base == sender.email.domain.sld
    // account for near-matches
    or (
      length(subject.base) < length(sender.email.domain.sld)
      and any([subject.base], strings.icontains(sender.email.domain.sld, .))
    )
  )
  // blank subject with recipient SLD in message body
  or (
    (length(subject.base) == 0 or subject.base is null)
    and any(recipients.to,
            strings.istarts_with(body.current_thread.text, .email.domain.sld)
    )
  )
)
and (
  // body contains document sharing language
  regex.icontains(body.current_thread.text,
                  '\b(?:document\s+I\s+sent|proposal\s+document|(?:proposal|documents?)\s+for\s+your\s+(?:approval|consideration|review|signature)|see\s+the\s+below|document.*(?:review|posted)|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document|(?:review\s+and\s+)?sign\s+your\s+document|electronic\s+signature\s+required)\b'
  )
  or strings.icontains(body.current_thread.text, 'document I sent')
  or strings.icontains(body.current_thread.text, 'proposal document')
  or strings.icontains(body.current_thread.text, 'let me know what you think')
  // account for image-as-content
  or (
    length(body.current_thread.text) < 10
    and (
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\b(document\s+I\s+sent|proposal\s+document|see\s+the\s+below|document.*review|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'document I sent'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'proposal document'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'let me know what you think'
      )
    )
  )
)
// has links that look like file attachments but aren't
and any(filter(body.links,
               // display text looks like a file
               (
                 regex.icontains(.display_text,
                                 '\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)'
                 )
                 or regex.icontains(.display_text, '\d+kb|\d+mb')
                 or strings.icontains(.display_text, 'document')
                 or strings.icontains(.display_text, 'proposal')
                 or strings.icontains(.display_text, 'review')
                 // account for image-as-content
                 or (
                   length(body.current_thread.text) < 10
                   and length(body.links) == 1
                 )
               )
               // but the URL doesn't point to legitimate file sharing
               and .href_url.domain.root_domain not in (
                 "sharepoint.com",
                 "google.com",
                 "dropbox.com",
                 "box.com",
                 "onedrive.com",
                 "1drv.ms",
                 "aka.ms",
                 "microsoft.com",
                 "office.com",
                 "docusign.com",
                 "adobesign.com",
                 "hellosign.com",
                 "signable.app"
               )
               and .href_url.domain.domain not in ("drive.google.com")
        ),
        // and points to suspicious domains
        .href_url.domain.tld in $suspicious_tlds
        or .href_url.domain.root_domain in $url_shorteners
        or .href_url.domain.domain in $url_shorteners
        or .href_url.domain.root_domain in $free_file_hosts
        or .href_url.domain.domain in $free_file_hosts
        // or it's a forms/survey platform being abused in self_service_creation_platform_domains
        or .href_url.domain.root_domain in $self_service_creation_platform_domains
        or .href_url.domain.domain in $self_service_creation_platform_domains
        // bulk mailer abuse has been observed
        or (
          (
            .href_url.domain.root_domain in $bulk_mailer_url_root_domains
            or (
              .href_url.rewrite.original is not null
              and 'mandrill' in .href_url.rewrite.encoders
            )
          )
          and .href_url.domain.sld not in $org_slds
        )
        // or the page redirects to common website, observed when evasion happens
        or (
          length(ml.link_analysis(., mode="aggressive").redirect_history) > 0
          and ml.link_analysis(., mode="aggressive").effective_url.domain.root_domain in $tranco_10k
        )
        // or common email marketing/tracking patterns
        or regex.match(.href_url.url, 'url\d+\..*\.com/ls/click')
        or regex.match(.href_url.path, '/ls/click|/click|/c/')
)
// 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().solicited == false
  or profile.by_sender_email().prevalence == "new"
  or profile.by_sender_email().days_since.last_contact > 30
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
  // or it's a spoof of the org_domain
  or (
    sender.email.domain.domain in $org_domains
    and not (
      headers.auth_summary.spf.pass
      or coalesce(headers.auth_summary.dmarc.pass, false)
    )
  )
)
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

Detects credential phishing attempts using generic document sharing language where the sender claims to have sent a document for review, but the link doesn't point to legitimate file sharing services.

  1. inbound message
  2. any of:
    • not:
      • length(body.previous_threads) > 0
    • all of:
      • length(recipients.to) is 1
      • length(recipients.cc) is 0
      • sender.email.email is recipients.to[0].email.email
  3. any of:
    • subject.base matches '\\b(has\\s+sent\\s+you|sent\\s+you|shared\\s+with\\s+you|document\\s+to\\s+review|document\\s*(number|num|#)|file\\s+to\\s+review|proposal\\s+(?:document|submission)|new\\s+document|document\\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\\s+(?:transfer|shared))\\b'
    • subject.subject contains 'document to review'
    • subject.subject contains 'file to review'
    • subject.subject contains 'sent you'
    • subject.subject contains 'eDocuments Notification'
    • any of:
      • subject.base is sender.email.domain.sld
      • all of:
        • length(subject.base) < length(sender.email.domain.sld)
        • any of [subject.base] where:
          • strings.icontains(sender.email.domain.sld)
    • all of:
      • any of:
        • length(subject.base) is 0
        • subject.base is missing
      • any of recipients.to where:
        • strings.istarts_with(body.current_thread.text)
  4. any of:
    • body.current_thread.text matches '\\b(?:document\\s+I\\s+sent|proposal\\s+document|(?:proposal|documents?)\\s+for\\s+your\\s+(?:approval|consideration|review|signature)|see\\s+the\\s+below|document.*(?:review|posted)|file.*review|let\\s+me\\s+know\\s+what\\s+you\\s+think|shared.{0,50}document|(?:review\\s+and\\s+)?sign\\s+your\\s+document|electronic\\s+signature\\s+required)\\b'
    • body.current_thread.text contains 'document I sent'
    • body.current_thread.text contains 'proposal document'
    • body.current_thread.text contains 'let me know what you think'
    • all of:
      • length(body.current_thread.text) < 10
      • any of:
        • beta.ocr(file.message_screenshot()).text matches '\\b(document\\s+I\\s+sent|proposal\\s+document|see\\s+the\\s+below|document.*review|file.*review|let\\s+me\\s+know\\s+what\\s+you\\s+think|shared.{0,50}document)\\b'
        • beta.ocr(file.message_screenshot()).text contains 'document I sent'
        • beta.ocr(file.message_screenshot()).text contains 'proposal document'
        • beta.ocr(file.message_screenshot()).text contains 'let me know what you think'
  5. any of filter(body.links) where any holds:
    • .href_url.domain.tld in $suspicious_tlds
    • .href_url.domain.root_domain in $url_shorteners
    • .href_url.domain.domain in $url_shorteners
    • .href_url.domain.root_domain in $free_file_hosts
    • .href_url.domain.domain in $free_file_hosts
    • .href_url.domain.root_domain in $self_service_creation_platform_domains
    • .href_url.domain.domain in $self_service_creation_platform_domains
    • all of:
      • any of:
        • .href_url.domain.root_domain in $bulk_mailer_url_root_domains
        • all of:
          • .href_url.rewrite.original is set
          • .href_url.rewrite.encoders contains 'mandrill'
      • .href_url.domain.sld not in $org_slds
    • all of:
      • length(ml.link_analysis(., mode='aggressive').redirect_history) > 0
      • ml.link_analysis(.).effective_url.domain.root_domain in $tranco_10k
    • .href_url.url matches 'url\\d+\\..*\\.com/ls/click'
    • .href_url.path matches '/ls/click|/click|/c/'
  6. 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
  7. any of:
    • profile.by_sender().solicited is False
    • profile.by_sender_email().prevalence is 'new'
    • profile.by_sender_email().days_since.last_contact > 30
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
    • all of:
      • sender.email.domain.domain in $org_domains
      • none of:
        • headers.auth_summary.spf.pass
        • coalesce(headers.auth_summary.dmarc.pass)
  8. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.previous_threads, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, recipients.cc, recipients.to, recipients.to[0].email.email, recipients.to[].email.domain.sld, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.domain.sld, sender.email.email, subject.base, subject.subject, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.link_analysis, profile.by_sender, profile.by_sender_email, regex.icontains, regex.match, strings.icontains, strings.istarts_with. Reference lists: $bulk_mailer_url_root_domains, $free_file_hosts, $high_trust_sender_root_domains, $org_domains, $org_slds, $self_service_creation_platform_domains, $suspicious_tlds, $tranco_10k, $url_shorteners.

Indicators matched (18)

FieldMatchValue
regex.icontainsregex\b(has\s+sent\s+you|sent\s+you|shared\s+with\s+you|document\s+to\s+review|document\s*(number|num|#)|file\s+to\s+review|proposal\s+(?:document|submission)|new\s+document|document\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b
strings.icontainssubstringdocument to review
strings.icontainssubstringfile to review
strings.icontainssubstringsent you
strings.icontainssubstringeDocuments Notification
regex.icontainsregex\b(?:document\s+I\s+sent|proposal\s+document|(?:proposal|documents?)\s+for\s+your\s+(?:approval|consideration|review|signature)|see\s+the\s+below|document.*(?:review|posted)|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document|(?:review\s+and\s+)?sign\s+your\s+document|electronic\s+signature\s+required)\b
strings.icontainssubstringdocument I sent
strings.icontainssubstringproposal document
strings.icontainssubstringlet me know what you think
regex.icontainsregex\b(document\s+I\s+sent|proposal\s+document|see\s+the\s+below|document.*review|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b
regex.icontainsregex\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)
regex.icontainsregex\d+kb|\d+mb
6 more
strings.icontainssubstringdocument
strings.icontainssubstringproposal
strings.icontainssubstringreview
filter(body.links)[].href_url.rewrite.encoderscontainsmandrill
regex.matchregexurl\d+\..*\.com/ls/click
regex.matchregex/ls/click|/click|/c/

Stages and Predicates

Stage 1: mql_rule

and
  any(filter(body.links))
    or
      and
        or
          and
            filter(body.links).href_url.rewrite.encoders contains "mandrill"
            filter(body.links).href_url.rewrite.original is_not_null
           macro "filter(body.links)[].href_url.domain.root_domain in bulk_mailer_url_root_domains"
         macro "filter(body.links)[].href_url.domain.sld not in org_slds"
      and
        ml.link_analysis func_call "ml.link_analysis(filter(body.links)[]).effective_url.domain.root_domain in tranco_10k"
        ml.link_analysis(filter(body.links)[], mode='aggressive').redirect_history length_compare "0"
      filter(body.links).href_url.path regex_match "/ls/click|/click|/c/"
      filter(body.links).href_url.url regex_match "url\\d+\\..*\\.com/ls/click"
       macro "filter(body.links)[].href_url.domain.domain in free_file_hosts"
       macro "filter(body.links)[].href_url.domain.domain in self_service_creation_platform_domains"
       macro "filter(body.links)[].href_url.domain.domain in url_shorteners"
       macro "filter(body.links)[].href_url.domain.root_domain in free_file_hosts"
       macro "filter(body.links)[].href_url.domain.root_domain in self_service_creation_platform_domains"
       macro "filter(body.links)[].href_url.domain.root_domain in url_shorteners"
       macro "filter(body.links)[].href_url.domain.tld in suspicious_tlds"
  or
    and
      not
        or
          coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
          headers.auth_summary.spf.pass eq "true"
       macro "sender.email.domain.domain in org_domains"
    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"
    profile.by_sender func_call "profile.by_sender().solicited == false"
    profile.by_sender_email func_call "profile.by_sender_email().days_since.last_contact > 30"
    profile.by_sender_email func_call "profile.by_sender_email().prevalence == new"
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "document I sent"
        beta.ocr(file.message_screenshot()).text contains "let me know what you think"
        beta.ocr(file.message_screenshot()).text contains "proposal document"
        beta.ocr(file.message_screenshot()).text regex_match "\\b(document\\s+I\\s+sent|proposal\\s+document|see\\s+the\\s+below|document.*review|file.*review|let\\s+me\\s+know\\s+what\\s+you\\s+think|shared.{0,50}document)\\b"
      body.current_thread.text length_compare "10"
    body.current_thread.text contains "document I sent"
    body.current_thread.text contains "let me know what you think"
    body.current_thread.text contains "proposal document"
    body.current_thread.text regex_match "\\b(?:document\\s+I\\s+sent|proposal\\s+document|(?:proposal|documents?)\\s+for\\s+your\\s+(?:approval|consideration|review|signature)|see\\s+the\\s+below|document.*(?:review|posted)|file.*review|let\\s+me\\s+know\\s+what\\s+you\\s+think|shared.{0,50}document|(?:review\\s+and\\s+)?sign\\s+your\\s+document|electronic\\s+signature\\s+required)\\b"
  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
      any([subject.base])
        strings.icontains func_call "strings.icontains(sender.email.domain.sld)"
      length func_call "length(subject.base) < length(sender.email.domain.sld)"
    and
      any(recipients.to)
        strings.istarts_with func_call "strings.istarts_with(body.current_thread.text)"
      or
        subject.base is_null
        subject.base length_compare "0"
    subject.base cross_field_compare "sender.email.domain.sld"
    subject.base regex_match "\\b(has\\s+sent\\s+you|sent\\s+you|shared\\s+with\\s+you|document\\s+to\\s+review|document\\s*(number|num|#)|file\\s+to\\s+review|proposal\\s+(?:document|submission)|new\\s+document|document\\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\\s+(?:transfer|shared))\\b"
    subject.subject contains "document to review"
    subject.subject contains "eDocuments Notification"
    subject.subject contains "file to review"
    subject.subject contains "sent you"
  or
    not
      body.previous_threads 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"
  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.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • document I sent
  • let me know what you think
  • proposal document
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • \b(document\s+I\s+sent|proposal\s+document|see\s+the\s+below|document.*review|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match value:"\b(document\s+I\s+sent|proposal\s+document|see\s+the\s+below|document.*review|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b"
body.current_thread.textcontains
  • document I sent
  • let me know what you think
  • proposal document
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • \b(?:document\s+I\s+sent|proposal\s+document|(?:proposal|documents?)\s+for\s+your\s+(?:approval|consideration|review|signature)|see\s+the\s+below|document.*(?:review|posted)|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document|(?:review\s+and\s+)?sign\s+your\s+document|electronic\s+signature\s+required)\b
field:"body.current_thread.text" kind:regex_match value:"\b(?:document\s+I\s+sent|proposal\s+document|(?:proposal|documents?)\s+for\s+your\s+(?:approval|consideration|review|signature)|see\s+the\s+below|document.*(?:review|posted)|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document|(?:review\s+and\s+)?sign\s+your\s+document|electronic\s+signature\s+required)\b"
sender.email.emailcross_field_compare
  • recipients.to[0].email.email transforms: op:eq
field:"sender.email.email" kind:cross_field_compare value:"recipients.to[0].email.email"
subject.basecross_field_compare
  • sender.email.domain.sld transforms: op:eq
field:"subject.base" kind:cross_field_compare value:"sender.email.domain.sld"
subject.baseis_null
  • (no value, null check)
field:"subject.base" kind:is_null
subject.baseregex_match
  • \b(has\s+sent\s+you|sent\s+you|shared\s+with\s+you|document\s+to\s+review|document\s*(number|num|#)|file\s+to\s+review|proposal\s+(?:document|submission)|new\s+document|document\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b
field:"subject.base" kind:regex_match value:"\b(has\s+sent\s+you|sent\s+you|shared\s+with\s+you|document\s+to\s+review|document\s*(number|num|#)|file\s+to\s+review|proposal\s+(?:document|submission)|new\s+document|document\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b"
subject.subjectcontains
  • document to review
  • eDocuments Notification
  • file to review
  • sent you
field:"subject.subject" kind:contains
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Hyper-linked image leading to free file host

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

This rule detects messages with short or null bodies, where all attachments are images, and the image is hyperlinking to a free_file_host from an unsolicited and untrusted sender.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, Free file host, Image as content, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.links
  • headers
  • headers.hops
  • sender.email
  • type

Rule body

type.inbound
and length(body.links) > 0
and 0 < length(attachments) < 8
and all(attachments, .file_type in $file_types_images and .size > 2000)
and any(body.links,
        // fingerprints of a hyperlinked image
        .display_text is null
        and .display_url.url is null
        and .href_url.domain.root_domain in $free_file_hosts
)
and (
  // body text is very short
  (
    0 <= (length(body.current_thread.text)) < 10
    or body.current_thread.text is null
  )
  or (
    length(body.current_thread.text) < 900
    // or body is most likely all warning banner (text contains the sender and common warning banner language)
    and (
      (
        strings.contains(body.current_thread.text, sender.email.email)
        and strings.contains(body.current_thread.text, 'caution')
      )
      or regex.icontains(body.current_thread.text,
                         "intended recipient's use only|external email|sent from outside|you don't often|confidential"
      )
    )
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

// not solicited or previously flagged malicious/spam
and (
  not profile.by_sender().solicited
  or profile.by_sender().any_messages_malicious_or_spam
)

// negate legitimate canva emails
and not (
  strings.contains(sender.display_name, "via Canva")
  and sender.email.domain.domain == "canva.com"
  and (
    any(distinct(headers.hops, .authentication_results.dmarc is not null),
        strings.ilike(.authentication_results.dmarc, "*pass")
    )
  )
)

Detection logic

Scope: inbound message.

This rule detects messages with short or null bodies, where all attachments are images, and the image is hyperlinking to a free_file_host from an unsolicited and untrusted sender.

  1. inbound message
  2. length(body.links) > 0
  3. all of:
    • length(attachments) > 0
    • length(attachments) < 8
  4. all of attachments where all hold:
    • .file_type in $file_types_images
    • .size > 2000
  5. any of body.links where all hold:
    • .display_text is missing
    • .display_url.url is missing
    • .href_url.domain.root_domain in $free_file_hosts
  6. any of:
    • any of:
      • all of:
        • length(body.current_thread.text) ≥ 0
        • length(body.current_thread.text) < 10
      • body.current_thread.text is missing
    • all of:
      • length(body.current_thread.text) < 900
      • any of:
        • all of:
          • strings.contains(body.current_thread.text)
          • body.current_thread.text contains 'caution'
        • body.current_thread.text matches "intended recipient's use only|external email|sent from outside|you don't often|confidential"
  7. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • any of distinct(headers.hops) where:
        • .authentication_results.dmarc matches '*fail'
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains
  8. any of:
    • not:
      • profile.by_sender().solicited
    • profile.by_sender().any_messages_malicious_or_spam
  9. not:
    • all of:
      • sender.display_name contains 'via Canva'
      • sender.email.domain.domain is 'canva.com'
      • any of distinct(headers.hops) where:
        • .authentication_results.dmarc matches '*pass'

Inspects: attachments[].file_type, attachments[].size, body.current_thread.text, body.links, body.links[].display_text, body.links[].display_url.url, body.links[].href_url.domain.root_domain, headers.hops, headers.hops[].authentication_results.dmarc, sender.display_name, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.email, type.inbound. Sensors: profile.by_sender, regex.icontains, strings.contains, strings.ilike. Reference lists: $file_types_images, $free_file_hosts, $high_trust_sender_root_domains.

Indicators matched (3)

FieldMatchValue
strings.containssubstringcaution
regex.icontainsregexintended recipient's use only|external email|sent from outside|you don't often|confidential
strings.ilikesubstring*fail

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        and
          body.current_thread.text contains "caution"
          strings.contains func_call "strings.contains(body.current_thread.text)"
        body.current_thread.text regex_match "intended recipient's use only|external email|sent from outside|you don't often|confidential"
      body.current_thread.text length_compare "900"
    and
      body.current_thread.text length_compare "0"
      body.current_thread.text length_compare "10"
    body.current_thread.text is_null
  or
    and
      any(distinct(headers.hops))
        distinct(headers.hops).authentication_results.dmarc ends_with "fail"
       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"
  not
    and
      any(distinct(headers.hops))
        distinct(headers.hops).authentication_results.dmarc ends_with "pass"
      sender.display_name contains "via Canva"
      sender.email.domain.domain eq "canva.com"
  any(body.links)
    and
      body.links.display_text is_null
      body.links.display_url.url is_null
       macro "body.links[].href_url.domain.root_domain in free_file_hosts"
  or
    not
      profile.by_sender func_call "profile.by_sender().solicited"
    profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
  attachments length_compare "0"
  attachments length_compare "8"
  body.links length_compare "0"
  type.inbound eq "true"
   macro "all(attachments)"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
distinct(headers.hops)array_any(no value, null check)excludes:distinct(headers.hops)
sender.display_namecontainsvia Canvaexcludes:sender.display_name field:"sender.display_name" value:"via Canva"
sender.email.domain.domaineqcanva.comexcludes:sender.email.domain.domain field:"sender.email.domain.domain" value:"canva.com"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • caution
field:"body.current_thread.text" kind:contains value:"caution"
body.current_thread.textis_null
  • (no value, null check)
field:"body.current_thread.text" kind:is_null
body.current_thread.textregex_match
    • intended recipient's use only
    • external email
    • sent from outside
    • you don't often
    • confidential
field:"body.current_thread.text" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Onedrive impersonation

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

This rule detects messages impersonating Microsoft's OneDrive service with medium to high credential theft language in the current thread. The subject is inspected for one drive language, with additional checks for free_subdomain hosted links, additional suspicious subject language or suspicious display text language.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree subdomain host, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • headers.hops
  • sender.email
  • subject
  • type

Rule body

type.inbound
// one drive is found in the sender display name or sender local part
and (
  (
    regex.icontains(sender.display_name, '[0o]ne\s?dr[il1]ve')
    or regex.icontains(sender.email.local_part, '[0o]ne\s?dr[il1]ve')
    or 0 < strings.ilevenshtein(strings.replace_confusables(sender.display_name),
                                "one?drive"
    ) < 2
    or any(attachments,
           (
             regex.icontains(.file_name, '[0o]ne\s?dr[il1]ve')
             and not any(file.explode(.),
                         any(.scan.exiftool.fields,
                             .key == "Model"
                             or (
                               .key == "Software"
                               and strings.starts_with(.value, "Android")
                             )
                         )
                         // exclude images taken with mobile cameras and screenshots from Apple
                         or any(.scan.exiftool.fields,
                                .key == "DeviceManufacturer"
                                and .value == "Apple Computer Inc."
                         )
             )
           )
           // pdf with OneDrive impersonation
           or (
             .file_type == "pdf"
             and any(ml.logo_detect(.).brands, .name == "Microsoft")
             and any(file.explode(.),
                     any(.scan.strings.strings,
                         strings.icontains(., "shared a file")
                     )
             )
           )
    )
  )
  or regex.imatch(strings.replace_confusables(body.current_thread.text),
                  '[0o]ne\s?dr[il1]ve.*'
  )
  // or one drive is in the subject with a freefile host, additional suspicious language, or suspicious display text
  or (
    regex.icontains(strings.replace_confusables(subject.subject),
                    '[0o]ne\s?dr[il1]ve'
    )
    and (
      any(body.links,
          .href_url.domain.root_domain in $free_subdomain_hosts
          and .href_url.domain.subdomain is not null
          and .href_url.domain.subdomain != "www"
      )
      or regex.icontains(subject.base, '(?:shared.{0,30}document)')
      or any(body.links,
             regex.icontains(.display_text,
                             "((view|show|access).(?:report|document)|review doc|view doc|view.attached)"
             )
      )
    )
  )
  or (
    any(ml.nlu_classifier(body.current_thread.text).topics,
        .name == "File Sharing and Cloud Services" and .confidence == "high"
    )
    // more than half of the links with display text contain the keyword "onedrive"
    and ratio(filter(body.links, .display_text is not null),
              regex.icontains(.display_text, '[0o]ne\s?dr[il1]ve')
    ) > 0.5
  )
  or (
    any(body.current_thread.links,
        any(ml.logo_detect(ml.link_analysis(.).screenshot).brands,
            .name == "Microsoft OneDrive" and .confidence in ("medium", "high")
        )
        and ml.link_analysis(.).effective_url.domain.root_domain in $free_subdomain_hosts
    )
    and regex.icontains(body.current_thread.text, '[0o]ne\s?dr[il1]ve')
  )
)
// and body language is med/high confidence cred theft
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name == "cred_theft" and .confidence in ("medium", "high")
  )
  or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
         .name == "cred_theft" and .confidence in ("medium", "high")
  )
  or any(body.current_thread.links,
         ml.link_analysis(.).credphish.disposition == "phishing"
  )
)
and length(body.links) < 10
and not (
  sender.email.domain.root_domain in (
    "bing.com",
    "microsoft.com",
    "microsoftonline.com",
    "microsoftsupport.com",
    "microsoft365.com",
    "office.com",
    "onedrive.com",
    "sharepointonline.com",
    "yammer.com",
  )
  and coalesce(headers.auth_summary.dmarc.pass, false)
)
// 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)
)
// excludes docusign senders that contain "via" in the display name
and not (
  any(headers.hops,
      any(.fields,
          .name == "X-Api-Host" and strings.ends_with(.value, "docusign.net")
      )
  )
  and strings.contains(sender.display_name, "via")
)
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

This rule detects messages impersonating Microsoft's OneDrive service with medium to high credential theft language in the current thread. The subject is inspected for one drive language, with additional checks for free_subdomain hosted links, additional suspicious subject language or suspicious display text language.

  1. inbound message
  2. any of:
    • any of:
      • sender.display_name matches '[0o]ne\\s?dr[il1]ve'
      • sender.email.local_part matches '[0o]ne\\s?dr[il1]ve'
      • all of:
        • strings.replace_confusables(sender.display_name) is similar to 'one?drive'
        • strings.replace_confusables(sender.display_name) is similar to 'one?drive'
      • any of attachments where any holds:
        • all of:
          • .file_name matches '[0o]ne\\s?dr[il1]ve'
          • not:
            • any of file.explode(.) where any holds:
              • any of .scan.exiftool.fields where any holds:
                • .key is 'Model'
                • all of:
                  • .key is 'Software'
                  • .value starts with 'Android'
              • any of .scan.exiftool.fields where all hold:
                • .key is 'DeviceManufacturer'
                • .value is 'Apple Computer Inc.'
        • all of:
          • .file_type is 'pdf'
          • any of ml.logo_detect(.).brands where:
            • .name is 'Microsoft'
          • any of file.explode(.) where:
            • any of .scan.strings.strings where:
              • . contains 'shared a file'
    • strings.replace_confusables(body.current_thread.text) matches '[0o]ne\\s?dr[il1]ve.*'
    • all of:
      • strings.replace_confusables(subject.subject) matches '[0o]ne\\s?dr[il1]ve'
      • any of:
        • any of body.links where all hold:
          • .href_url.domain.root_domain in $free_subdomain_hosts
          • .href_url.domain.subdomain is set
          • .href_url.domain.subdomain is not 'www'
        • subject.base matches '(?:shared.{0,30}document)'
        • any of body.links where:
          • .display_text matches '((view|show|access).(?:report|document)|review doc|view doc|view.attached)'
    • all of:
      • any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
        • .name is 'File Sharing and Cloud Services'
        • .confidence is 'high'
      • ratio(filter(body.links, .display_text is not null)) > 0.5
    • all of:
      • any of body.current_thread.links where all hold:
        • any of ml.logo_detect(ml.link_analysis(.).screenshot).brands where all hold:
          • .name is 'Microsoft OneDrive'
          • .confidence in ('medium', 'high')
        • ml.link_analysis(.).effective_url.domain.root_domain in $free_subdomain_hosts
      • body.current_thread.text matches '[0o]ne\\s?dr[il1]ve'
  3. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'cred_theft'
      • .confidence in ('medium', 'high')
    • any of ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents where all hold:
      • .name is 'cred_theft'
      • .confidence in ('medium', 'high')
    • any of body.current_thread.links where:
      • ml.link_analysis(.).credphish.disposition is 'phishing'
  4. length(body.links) < 10
  5. not:
    • all of:
      • sender.email.domain.root_domain in ('bing.com', 'microsoft.com', 'microsoftonline.com', 'microsoftsupport.com', 'microsoft365.com', 'office.com', 'onedrive.com', 'sharepointonline.com', 'yammer.com')
      • coalesce(headers.auth_summary.dmarc.pass)
  6. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass)
  7. not:
    • all of:
      • any of headers.hops where:
        • any of .fields where all hold:
          • .name is 'X-Api-Host'
          • .value ends with 'docusign.net'
      • sender.display_name contains 'via'
  8. not:
    • profile.by_sender().any_messages_benign

Inspects: attachments[].file_name, attachments[].file_type, body.current_thread.links, body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, body.links[].href_url.domain.subdomain, headers.auth_summary.dmarc.pass, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, sender.display_name, sender.email.domain.root_domain, sender.email.local_part, subject.base, subject.subject, type.inbound. Sensors: beta.ocr, file.explode, file.message_screenshot, ml.link_analysis, ml.logo_detect, ml.nlu_classifier, profile.by_sender, regex.icontains, regex.imatch, strings.contains, strings.ends_with, strings.icontains, strings.ilevenshtein, strings.replace_confusables, strings.starts_with. Reference lists: $free_subdomain_hosts, $high_trust_sender_root_domains.

Indicators matched (19)

FieldMatchValue
regex.icontainsregex[0o]ne\s?dr[il1]ve
strings.ilevenshteinfuzzyone?drive
attachments[].file_typeequalspdf
ml.logo_detect(attachments[]).brands[].nameequalsMicrosoft
strings.icontainssubstringshared a file
regex.imatchregex[0o]ne\s?dr[il1]ve.*
regex.icontainsregex(?:shared.{0,30}document)
regex.icontainsregex((view|show|access).(?:report|document)|review doc|view doc|view.attached)
ml.nlu_classifier(body.current_thread.text).topics[].nameequalsFile Sharing and Cloud Services
ml.nlu_classifier(body.current_thread.text).topics[].confidenceequalshigh
ml.logo_detect(ml.link_analysis(body.current_thread.links[]).screenshot).brands[].nameequalsMicrosoft OneDrive
ml.logo_detect(ml.link_analysis(body.current_thread.links[]).screenshot).brands[].confidencemembermedium
7 more
ml.logo_detect(ml.link_analysis(body.current_thread.links[]).screenshot).brands[].confidencememberhigh
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidencemembermedium
ml.nlu_classifier(body.current_thread.text).intents[].confidencememberhigh
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].nameequalscred_theft
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidencemembermedium
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidencememberhigh

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(attachments)
      or
        and
          not
            any(file.explode(attachments))
              or
                any(file.explode(attachments).scan.exiftool.fields)
                  or
                    and
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "Software"
                      file.explode(attachments[])[].scan.exiftool.fields[].value starts_with "Android"
                    file.explode(attachments[])[].scan.exiftool.fields[].key eq "Model"
                any(file.explode(attachments).scan.exiftool.fields)
                  and
                    file.explode(attachments[])[].scan.exiftool.fields[].key eq "DeviceManufacturer"
                    file.explode(attachments[])[].scan.exiftool.fields[].value eq "Apple Computer Inc."
          attachments.file_name regex_match "[0o]ne\\s?dr[il1]ve"
        and
          any(file.explode(attachments))
            any(file.explode(attachments).scan.strings.strings)
              file.explode(attachments).scan.strings.strings contains "shared a file"
          any(ml.logo_detect(attachments).brands)
            ml.logo_detect(attachments).brands.name eq "Microsoft"
          attachments.file_type eq "pdf"
    and
      any(body.current_thread.links)
        and
          any(ml.logo_detect(ml.link_analysis(body.current_thread.links).screenshot).brands)
            and
              ml.logo_detect(ml.link_analysis(body.current_thread.links[]).screenshot).brands[].confidence in ["high", "medium"]
              ml.logo_detect(ml.link_analysis(body.current_thread.links[]).screenshot).brands[].name eq "Microsoft OneDrive"
          ml.link_analysis func_call "ml.link_analysis(body.current_thread.links[]).effective_url.domain.root_domain in free_subdomain_hosts"
      body.current_thread.text regex_match "[0o]ne\\s?dr[il1]ve"
    and
      or
        any(body.links)
          and
            body.links.href_url.domain.subdomain is_not_null
            body.links.href_url.domain.subdomain ne "www"
             macro "body.links[].href_url.domain.root_domain in free_subdomain_hosts"
        any(body.links)
          body.links.display_text regex_match "((view|show|access).(?:report|document)|review doc|view doc|view.attached)"
        subject.base regex_match "(?:shared.{0,30}document)"
      strings.replace_confusables(subject.subject) regex_match "[0o]ne\\s?dr[il1]ve"
    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 "File Sharing and Cloud Services"
      ratio func_call "ratio(filter(body.links, .display_text is not null)) > 0.5"
    and
      strings.ilevenshtein func_call "strings.ilevenshtein(strings.replace_confusables(sender.display_name), \"one?drive\") < 2"
      strings.ilevenshtein func_call "strings.ilevenshtein(strings.replace_confusables(sender.display_name), \"one?drive\") > 0"
    sender.display_name regex_match "[0o]ne\\s?dr[il1]ve"
    sender.email.local_part regex_match "[0o]ne\\s?dr[il1]ve"
    strings.replace_confusables(body.current_thread.text) regex_match "[0o]ne\\s?dr[il1]ve.*"
  not
    and
      any(headers.hops)
        any(headers.hops.fields)
          and
            headers.hops.fields[].name eq "X-Api-Host"
            headers.hops.fields[].value ends_with "docusign.net"
      sender.display_name contains "via"
  or
    any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents)
      and
        ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents.confidence in ["high", "medium"]
        ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents.name eq "cred_theft"
    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 "cred_theft"
    any(body.current_thread.links)
      ml.link_analysis func_call "ml.link_analysis(body.current_thread.links[]).credphish.disposition == phishing"
  not
    and
      coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
      sender.email.domain.root_domain in ["bing.com", "microsoft.com", "microsoft365.com", "microsoftonline.com", "microsoftsupport.com", "office.com", "onedrive.com", "sharepointonline.com", "yammer.com"]
  not
    and
      coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  body.links length_compare "10"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.hopsarray_any(no value, null check)excludes:headers.hops
sender.display_namecontainsviaexcludes:sender.display_name field:"sender.display_name" value:"via"
sender.email.domain.root_domaininbing.com, microsoft.com, microsoft365.com, microsoftonline.com, microsoftsupport.com, office.com, onedrive.com, sharepointonline.com, yammer.comexcludes:sender.email.domain.root_domain

Indicators

These rows show field, operator, and value matches.

Credential phishing: Re-Authentication lure

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Contains suspicious links and server-related terminology, requesting email account reauthentication with language targeting recipient credentials.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering, Impersonation: Brand

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • recipients
  • recipients.to
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(body.current_thread.text) < 2000
and length(body.links) < 10
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name == "cred_theft" and .confidence == "high"
  )
  or ml.nlu_classifier(body.current_thread.text).language != "english"
)
and any(ml.nlu_classifier(body.current_thread.text).topics,
        .name == "Security and Authentication" and .confidence == "high"
)

// email server language
and 3 of (
  strings.icontains(body.current_thread.text, "security token"),
  strings.icontains(body.current_thread.text, "still active"),
  any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency"),
  regex.icontains(body.current_thread.text, 're[- ]?activat(e|ing)'),
  regex.contains(body.current_thread.text, '\bMX\b'),
  strings.icontains(body.current_thread.text, "mail servers"),
  strings.icontains(body.current_thread.text, "email termination"),
  strings.icontains(body.current_thread.text, "locked out"),
  strings.icontains(body.current_thread.text, "email account"),
  strings.icontains(body.current_thread.text, "credential"),
  strings.icontains(subject.base, "disconnection"),
  any(recipients.to,
      .email.domain.valid and strings.icontains(subject.base, .email.email)
  ),
  any(recipients.to,
      .email.domain.valid
      and strings.icontains(body.current_thread.text,
                            strings.concat("dear ", .email.local_part)
      )
  ),
  any(recipients.to,
      .email.domain.valid
      and strings.icontains(body.current_thread.text,
                            strings.concat(.email.domain.root_domain, " server")
      )
  ),
  any(recipients.to,
      .email.domain.valid
      and strings.icontains(body.current_thread.text,
                            strings.concat(.email.domain.root_domain,
                                           "  server"
                            )
      )
  ),
  any(recipients.to,
      .email.domain.valid
      and strings.icontains(body.current_thread.text,
                            strings.concat("attn: ", .email.local_part)
      )
  ),
  any(recipients.to,
      .email.domain.valid
      and strings.icount(body.current_thread.text, .email.email) > 1
  )
)

// suspicious link
and 2 of (
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      regex.match(.display_text, '[A-Z ]+')
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      strings.icontains(.display_text, 'update')
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      strings.icontains(.display_text, 'confirm')
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      strings.icontains(.display_text, 'resolve')
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      strings.icontains(.display_text, 'auth')
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      .href_url.domain.root_domain == "ru.com"
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      .href_url.path == "/lt.php"
  ),
  any(filter(body.links,
             .href_url.domain.root_domain != sender.email.domain.root_domain
      ),
      .href_url.domain.tld in $suspicious_tlds
  ),
  any(recipients.to,
      .email.domain.valid
      and any(filter(body.links,
                     .href_url.domain.root_domain != sender.email.domain.root_domain
              ),
              strings.icontains(.href_url.url, ..email.email)
      )
  ),
  any(recipients.to,
      .email.domain.valid
      and any(filter(body.links,
                     .href_url.domain.root_domain != sender.email.domain.root_domain
              ),
              strings.icontains(.display_text, ..email.email)
      )
  ),
  (
    any(filter(body.links,
               .href_url.domain.root_domain != sender.email.domain.root_domain
        ),
        .href_url.domain.domain in $free_file_hosts
    )
    or any(filter(body.links,
                  .href_url.domain.root_domain != sender.email.domain.root_domain
           ),
           .href_url.domain.root_domain in $free_file_hosts
    )
  ),
  (
    any(filter(body.links,
               .href_url.domain.root_domain != sender.email.domain.root_domain
        ),
        .href_url.domain.domain in $free_subdomain_hosts
    )
    or any(filter(body.links,
                  .href_url.domain.root_domain != sender.email.domain.root_domain
           ),
           .href_url.domain.root_domain in $free_subdomain_hosts
    )
  )
)
// and the sender is not from high trust sender root 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
)

Detection logic

Scope: inbound message.

Contains suspicious links and server-related terminology, requesting email account reauthentication with language targeting recipient credentials.

  1. inbound message
  2. length(body.current_thread.text) < 2000
  3. length(body.links) < 10
  4. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'cred_theft'
      • .confidence is 'high'
    • ml.nlu_classifier(body.current_thread.text).language is not 'english'
  5. any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
    • .name is 'Security and Authentication'
    • .confidence is 'high'
  6. at least 3 of:
    • body.current_thread.text contains 'security token'
    • body.current_thread.text contains 'still active'
    • any of ml.nlu_classifier(body.current_thread.text).entities where:
      • .name is 'urgency'
    • body.current_thread.text matches 're[- ]?activat(e|ing)'
    • body.current_thread.text matches '\\bMX\\b'
    • body.current_thread.text contains 'mail servers'
    • body.current_thread.text contains 'email termination'
    • body.current_thread.text contains 'locked out'
    • body.current_thread.text contains 'email account'
    • body.current_thread.text contains 'credential'
    • subject.base contains 'disconnection'
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icontains(subject.base)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icontains(body.current_thread.text)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icontains(body.current_thread.text)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icontains(body.current_thread.text)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icontains(body.current_thread.text)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • strings.icount(body.current_thread.text) > 1
  7. at least 2 of:
    • any of filter(body.links) where:
      • .display_text matches '[A-Z ]+'
    • any of filter(body.links) where:
      • .display_text contains 'update'
    • any of filter(body.links) where:
      • .display_text contains 'confirm'
    • any of filter(body.links) where:
      • .display_text contains 'resolve'
    • any of filter(body.links) where:
      • .display_text contains 'auth'
    • any of filter(body.links) where:
      • .href_url.domain.root_domain is 'ru.com'
    • any of filter(body.links) where:
      • .href_url.path is '/lt.php'
    • any of filter(body.links) where:
      • .href_url.domain.tld in $suspicious_tlds
    • any of recipients.to where all hold:
      • .email.domain.valid
      • any of filter(body.links) where:
        • strings.icontains(.href_url.url)
    • any of recipients.to where all hold:
      • .email.domain.valid
      • any of filter(body.links) where:
        • strings.icontains(.display_text)
    • any of:
      • any of filter(body.links) where:
        • .href_url.domain.domain in $free_file_hosts
      • any of filter(body.links) where:
        • .href_url.domain.root_domain in $free_file_hosts
    • any of:
      • any of filter(body.links) where:
        • .href_url.domain.domain in $free_subdomain_hosts
      • any of filter(body.links) where:
        • .href_url.domain.root_domain in $free_subdomain_hosts
  8. 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, body.links, body.links[].href_url.domain.root_domain, headers.auth_summary.dmarc.pass, recipients.to, recipients.to[].email.domain.root_domain, recipients.to[].email.domain.valid, recipients.to[].email.email, recipients.to[].email.local_part, sender.email.domain.root_domain, subject.base, type.inbound. Sensors: ml.nlu_classifier, regex.contains, regex.icontains, regex.match, strings.concat, strings.icontains, strings.icount. Reference lists: $free_file_hosts, $free_subdomain_hosts, $high_trust_sender_root_domains, $suspicious_tlds.

Indicators matched (22)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh
ml.nlu_classifier(body.current_thread.text).topics[].nameequalsSecurity and Authentication
ml.nlu_classifier(body.current_thread.text).topics[].confidenceequalshigh
strings.icontainssubstringsecurity token
strings.icontainssubstringstill active
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsurgency
regex.icontainsregexre[- ]?activat(e|ing)
regex.containsregex\bMX\b
strings.icontainssubstringmail servers
strings.icontainssubstringemail termination
strings.icontainssubstringlocked out
10 more
strings.icontainssubstringemail account
strings.icontainssubstringcredential
strings.icontainssubstringdisconnection
regex.matchregex[A-Z ]+
strings.icontainssubstringupdate
strings.icontainssubstringconfirm
strings.icontainssubstringresolve
strings.icontainssubstringauth
filter(body.links)[].href_url.domain.root_domainequalsru.com
filter(body.links)[].href_url.pathequals/lt.php

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(recipients.to)
      and
        any(filter(body.links))
          strings.icontains func_call "strings.icontains(filter(body.links)[].display_text)"
        recipients.to.email.domain.valid eq "true"
    any(recipients.to)
      and
        any(filter(body.links))
          strings.icontains func_call "strings.icontains(filter(body.links)[].href_url.url)"
        recipients.to.email.domain.valid eq "true"
    any(filter(body.links))
      filter(body.links).display_text contains "auth"
    any(filter(body.links))
      filter(body.links).display_text contains "confirm"
    any(filter(body.links))
      filter(body.links).display_text contains "resolve"
    any(filter(body.links))
      filter(body.links).display_text contains "update"
    any(filter(body.links))
      filter(body.links).display_text regex_match "[A-Z ]+"
    any(filter(body.links))
      filter(body.links).href_url.domain.root_domain eq "ru.com"
    any(filter(body.links))
      filter(body.links).href_url.path eq "/lt.php"
    any(filter(body.links))
       macro "filter(body.links)[].href_url.domain.domain in free_file_hosts"
    any(filter(body.links))
       macro "filter(body.links)[].href_url.domain.domain in free_subdomain_hosts"
    any(filter(body.links))
       macro "filter(body.links)[].href_url.domain.root_domain in free_file_hosts"
    any(filter(body.links))
       macro "filter(body.links)[].href_url.domain.root_domain in free_subdomain_hosts"
    any(filter(body.links))
       macro "filter(body.links)[].href_url.domain.tld in suspicious_tlds"
  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).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
    ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language != english"
  or
    any(recipients.to)
      and
        recipients.to.email.domain.valid eq "true"
        strings.icontains func_call "strings.icontains(body.current_thread.text)"
    any(recipients.to)
      and
        recipients.to.email.domain.valid eq "true"
        strings.icontains func_call "strings.icontains(subject.base)"
    any(recipients.to)
      and
        recipients.to.email.domain.valid eq "true"
        strings.icount func_call "strings.icount(body.current_thread.text) > 1"
    any(ml.nlu_classifier(body.current_thread.text).entities)
      ml.nlu_classifier(body.current_thread.text).entities.name eq "urgency"
    body.current_thread.text contains "credential"
    body.current_thread.text contains "email account"
    body.current_thread.text contains "email termination"
    body.current_thread.text contains "locked out"
    body.current_thread.text contains "mail servers"
    body.current_thread.text contains "security token"
    body.current_thread.text contains "still active"
    body.current_thread.text regex_match "\\bMX\\b"
    body.current_thread.text regex_match "re[- ]?activat(e|ing)"
    subject.base contains "disconnection"
  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 "Security and Authentication"
  body.current_thread.text length_compare "2000"
  body.links length_compare "10"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • credential
  • email account
  • email termination
  • locked out
  • mail servers
  • security token
  • still active
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • \bMX\b
  • re[- ]?activat(e|ing)
field:"body.current_thread.text" kind:regex_match
subject.basecontains
  • disconnection
field:"subject.base" kind:contains value:"disconnection"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Suspicious e-sign agreement document notification

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects phishing attempts disguised as e-signature requests, characterized by common document sharing phrases, unusual HTML padding, and suspicious link text.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • body.links
  • headers
  • headers.auth_summary
  • headers.hops
  • mailbox
  • recipients
  • recipients.to
  • sender.email
  • subject
  • type

Rule body

type.inbound
and any([subject.subject, sender.display_name],
        regex.icontains(strings.replace_confusables(.),
                        "D[0o]cuLink",
                        "Agreement",
                        "Access.&.Appr[0o]ved",
                        "Agreement.{0,5}Review",
                        "Attend.and.Review",
                        "action.re?quired",
                        "AuthentiSign",
                        "Completed.File",
                        "D[0o]chsared",
                        "D[0o]cshared",
                        "D[0o]csPoint",
                        "D[0o]cument.Shared",
                        "D[0o]cuCentre",
                        "D[0o]cuCenter",
                        "D[0o]cCenter",
                        "D[0o]csOnline",
                        "D[0o]cSend",
                        "D[0o]cu?Send",
                        "d[0o]csign",
                        "D[0o]cu-eSin",
                        "D[0o]cu-management",
                        "\\beSign",
                        "e\\.sign",
                        "esign.[0o]nline",
                        "[SsZz][lL][GgSs][Nn].*D[0o]c",
                        "e-d[0o]c",
                        "e-signature",
                        "e-Verify Doc",
                        "eSignature",
                        "eSign&Return",
                        "eSign[0o]nline",
                        "Fileshare",
                        "Review.and.C[0o]mplete",
                        "Review.&.Sign",
                        "Sign[0o]nline",
                        "Signature.Request",
                        "Shared.C[0o]mpleted",
                        "Sign.and.Seal",
                        "viaSign",
                        "D[0o]cuSign",
                        "D[0o]csID",
                        "Complete.{0,10}D[0o]cuSign",
                        "Enroll & Sign",
                        "Review and Sign",
                        "Sign(?:Report|Now)",
                        "SignD[0o]c",
                        "D[0o]cxxx",
                        "d[0o]cufile",
                        'E\x{00AD}-\x{00AD}S\x{00AD}i\x{00AD}g\x{00AD}n\x{00AD}&Return',
                        "d[0o]cument.signature",
                        "Electr[0o]nic.?Signature",
                        "Complete: ",
                        "Please (?:Review|Sign)",
                        "^REVIEW$",
                        "requests your signature",
                        "signature on.*contract",
                        "Independent Contract",
                        "Contract.*signature",
                        "add your signature",
                        "signature needed",
                        "attn_task",
                        "DocReq\\b"
        )
        or (
          regex.icontains(strings.replace_confusables(.), "action.re?quired")
          and not (
            sender.email.domain.root_domain == "sharepointonline.com"
            and headers.auth_summary.dmarc.pass
            and strings.icontains(subject.subject, "asked to edit")
          )
        )
)
and (
  // unusual repeated patterns in HTML
  regex.icontains(body.html.raw, '((<br\s*/?>\s*){20,}|\n{20,})')
  or regex.icontains(body.html.raw, '(<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}')
  or regex.icontains(body.html.raw,
                     '(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\s*){30,}'
  )
  or regex.icontains(body.html.raw, '(<p>&nbsp;</p>\s*){7,}')
  or regex.icontains(body.html.raw, '(<p[^>]*>\s*&nbsp;<br>\s*</p>\s*){5,}')
  or regex.icontains(body.html.raw, '(<p[^>]*>&nbsp;</p>\s*){7,}')
  or strings.count(body.html.raw, "&nbsp;\u{200C}&nbsp;\u{200C}&nbsp") > 50
  or regex.count(body.html.raw,
                 '<span\s*class\s*=\s*"[^\"]+"\s*>\s*[a-z]\s*<\/span><span\s*class\s*=\s*"[^\"]+"\s*>\s*[a-z]+\s*<\/span>'
  ) > 50
  // lookalike docusign
  or regex.icontains(body.html.raw, '>Docus[1l]gn<')
  or strings.icontains(body.current_thread.text, 'completed by all parties')
  or (
    regex.icontains(body.html.inner_text, 'Document')
    and length(body.html.inner_text) < 500
  )
  // common greetings via email.local_part
  or any(recipients.to,
         // use count to ensure the email address is not part of a disclaimer
         strings.icount(body.current_thread.text, .email.local_part) > 
         // sum allows us to add more logic as needed
         sum([
               strings.icount(body.current_thread.text,
                              strings.concat('was sent to ', .email.email)
               ),
               strings.icount(body.current_thread.text,
                              strings.concat('intended for ', .email.email)
               )
             ]
         )
  )
  // common greetings via mailbox display name
  or strings.icount(body.current_thread.text, mailbox.display_name) > 
  // sum allows us to add more logic as needed
  sum([
        strings.icount(body.current_thread.text,
                       strings.concat('was sent to ', mailbox.display_name)
        ),
        strings.icount(body.current_thread.text,
                       strings.concat('intended for ', mailbox.display_name)
        )
      ]
  )
  // Abnormally high count of mailto links in raw html
  or regex.count(body.html.raw,
                 'mailto:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}'
  ) > 50

  // High count of empty elements (padding)
  or regex.count(body.html.raw,
                 '<(?:p|div|span|td)[^>]*>\s*(?:&nbsp;|\s)*\s*</(?:p|div|span|td)>'
  ) > 30

  // HR impersonation
  or strings.ilike(sender.display_name, "HR", "H?R", "*Human Resources*")

  // Sender display name contains a phone number
  or regex.icontains(sender.display_name,
                     '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}'
  )
)
and (
  any(body.links,

      // suspicious content within link display_text
      regex.icontains(strings.replace_confusables(.display_text),
                      "activate",
                      "re-auth",
                      "verify",
                      "acknowledg",
                      "(keep|change).{0,20}(active|password|access)",
                      '((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)',
                      'use.same.pass',
                      'validate.{0,15}account',
                      'recover.{0,15}messages',
                      '(retry|update).{0,10}payment',
                      'check activity',
                      '(listen|play).{0,10}(vm|voice)',
                      'clarify.{0,20}(deposit|wallet|funds)',
                      'enter.{0,15}teams',
                      'Review and sign',
                      'REVIEW.*DOCUMENT',
                      'Open Document',
                      'Sign Now',
                      'complete tasks?'
      )
      // check that the display_text is all lowercase
      or (
        regex.contains(.display_text,
                       "\\bVIEW",
                       "DOWNLOAD",
                       "CHECK",
                       "KEEP.(SAME|MY)",
                       "VERIFY",
                       "ACCESS\\b",
                       "SIGN\\b",
                       "ENABLE\\b",
                       "RETAIN",
                       "PLAY",
                       "LISTEN",
        )
        and regex.match(.display_text, "^[^a-z]*[A-Z][^a-z]*$")
      )

      // the display text is _exactly_
      or .display_text in~ ("Open")

      // the display text is "go to documents" with the local part of recipient email in body
      or (
        strings.icontains(.display_text, "go to documents")
        and any(recipients.to,
                strings.contains(body.current_thread.text, .email.local_part)
        )
      )

      // URL fragment containing recipient's address
      or .href_url.fragment in map(recipients.to, .email.email)
  )
  // one hyperlinked image that's not a tracking pixel
  or (
    length(html.xpath(body.html,
                      "//a//img[(number(@width) > 5 or not(@width)) and (number(@height) > 5 or not(@height))]"
           ).nodes
    ) == 1
    and length(body.current_thread.text) < 500
  )
  or (
    length(attachments) > 0
    and any(attachments,
            (
              regex.icontains(beta.ocr(.).text,
                              "activate",
                              "re-auth",
                              "verify",
                              "acknowledg",
                              "(keep|change).{0,20}(active|password|access)",
                              '((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)',
                              'use.same.pass',
                              'validate.{0,15}account',
                              'recover.{0,15}messages',
                              '(retry|update).{0,10}payment',
                              'check activity',
                              '(listen|play).{0,10}(vm|voice)',
                              'clarify.{0,20}(deposit|wallet|funds)',
                              'enter.{0,15}teams',
                              'Review and sign'
              )
            )
            or (
              any(file.explode(.),
                  regex.icontains(.scan.ocr.raw,
                                  "activate",
                                  "re-auth",
                                  "verify",
                                  "acknowledg",
                                  "(keep|change).{0,20}(active|password|access)",
                                  '((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)',
                                  'use.same.pass',
                                  'validate.{0,15}account',
                                  'recover.{0,15}messages',
                                  '(retry|update).{0,10}payment',
                                  'check activity',
                                  '(listen|play).{0,10}(vm|voice)',
                                  'clarify.{0,20}(deposit|wallet|funds)',
                                  'enter.{0,15}teams',
                                  'Review and sign'
                  )
              )
            )
    )
  )
)
// the message is unsolicited and no false positives
and (
  not profile.by_sender_email().solicited
  or profile.by_sender_email().prevalence == "new"
  or (
    profile.by_sender_email().any_messages_malicious_or_spam
    and not profile.by_sender_email().any_messages_benign
  )
  or (
    profile.by_sender_email().any_messages_malicious_or_spam
    and profile.by_sender_email().any_messages_benign
    and (
      not headers.auth_summary.dmarc.pass or not headers.auth_summary.spf.pass
    )
  )
)

// negate replies/fowards containing legitimate docs
and not (length(headers.references) > 0 or headers.in_reply_to is not null)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

Detection logic

Scope: inbound message.

Detects phishing attempts disguised as e-signature requests, characterized by common document sharing phrases, unusual HTML padding, and suspicious link text.

  1. inbound message
  2. any of [subject.subject, sender.display_name] where any holds:
    • strings.replace_confusables(.) matches any of 62 patterns
      • D[0o]cuLink
      • Agreement
      • Access.&.Appr[0o]ved
      • Agreement.{0,5}Review
      • Attend.and.Review
      • action.re?quired
      • AuthentiSign
      • Completed.File
      • D[0o]chsared
      • D[0o]cshared
      • D[0o]csPoint
      • D[0o]cument.Shared
      • D[0o]cuCentre
      • D[0o]cuCenter
      • D[0o]cCenter
      • D[0o]csOnline
      • D[0o]cSend
      • D[0o]cu?Send
      • d[0o]csign
      • D[0o]cu-eSin
      • D[0o]cu-management
      • \\beSign
      • e\\.sign
      • esign.[0o]nline
      • [SsZz][lL][GgSs][Nn].*D[0o]c
      • e-d[0o]c
      • e-signature
      • e-Verify Doc
      • eSignature
      • eSign&Return
      • eSign[0o]nline
      • Fileshare
      • Review.and.C[0o]mplete
      • Review.&.Sign
      • Sign[0o]nline
      • Signature.Request
      • Shared.C[0o]mpleted
      • Sign.and.Seal
      • viaSign
      • D[0o]cuSign
      • D[0o]csID
      • Complete.{0,10}D[0o]cuSign
      • Enroll & Sign
      • Review and Sign
      • Sign(?:Report|Now)
      • SignD[0o]c
      • D[0o]cxxx
      • d[0o]cufile
      • E\x{00AD}-\x{00AD}S\x{00AD}i\x{00AD}g\x{00AD}n\x{00AD}&Return
      • d[0o]cument.signature
      • Electr[0o]nic.?Signature
      • Complete:
      • Please (?:Review|Sign)
      • ^REVIEW$
      • requests your signature
      • signature on.*contract
      • Independent Contract
      • Contract.*signature
      • add your signature
      • signature needed
      • attn_task
      • DocReq\\b
    • all of:
      • strings.replace_confusables(.) matches 'action.re?quired'
      • not:
        • all of:
          • sender.email.domain.root_domain is 'sharepointonline.com'
          • headers.auth_summary.dmarc.pass
          • subject.subject contains 'asked to edit'
  3. any of:
    • body.html.raw matches '((<br\\s*/?>\\s*){20,}|\\n{20,})'
    • body.html.raw matches '(<p[^>]*>\\s*<br\\s*/?>\\s*</p>\\s*){30,}'
    • body.html.raw matches '(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\\s*){30,}'
    • body.html.raw matches '(<p>&nbsp;</p>\\s*){7,}'
    • body.html.raw matches '(<p[^>]*>\\s*&nbsp;<br>\\s*</p>\\s*){5,}'
    • body.html.raw matches '(<p[^>]*>&nbsp;</p>\\s*){7,}'
    • strings.count(body.html.raw, '&nbsp;\\u{200C}&nbsp;\\u{200C}&nbsp') > 50
    • regex.count(body.html.raw, '<span\\s*class\\s*=\\s*"[^\\"]+"\\s*>\\s*[a-z]\\s*<\\/span><span\\s*class\\s*=\\s*"[^\\"]+"\\s*>\\s*[a-z]+\\s*<\\/span>') > 50
    • body.html.raw matches '>Docus[1l]gn<'
    • body.current_thread.text contains 'completed by all parties'
    • all of:
      • body.html.inner_text matches 'Document'
      • length(body.html.inner_text) < 500
    • any of recipients.to where:
      • strings.icount(body.current_thread.text) > sum([strings.icount(body.current_thread.text, strings.concat('was sent to ', .email.email)), strings.icount(body.current_thread.text, strings.concat('intended for ', .email.email))])
    • strings.icount(body.current_thread.text) > sum([strings.icount(body.current_thread.text, strings.concat('was sent to ', mailbox.display_name)), strings.icount(body.current_thread.text, strings.concat('intended for ', mailbox.display_name))])
    • regex.count(body.html.raw, 'mailto:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}') > 50
    • regex.count(body.html.raw, '<(?:p|div|span|td)[^>]*>\\s*(?:&nbsp;|\\s)*\\s*</(?:p|div|span|td)>') > 30
    • sender.display_name matches any of 3 patterns
      • HR
      • H?R
      • *Human Resources*
    • sender.display_name matches '\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}'
  4. any of:
    • any of body.links where any holds:
      • strings.replace_confusables(.display_text) matches any of 19 patterns
        • activate
        • re-auth
        • verify
        • acknowledg
        • (keep|change).{0,20}(active|password|access)
        • ((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)
        • use.same.pass
        • validate.{0,15}account
        • recover.{0,15}messages
        • (retry|update).{0,10}payment
        • check activity
        • (listen|play).{0,10}(vm|voice)
        • clarify.{0,20}(deposit|wallet|funds)
        • enter.{0,15}teams
        • Review and sign
        • REVIEW.*DOCUMENT
        • Open Document
        • Sign Now
        • complete tasks?
      • all of:
        • .display_text matches any of 11 patterns
          • \\bVIEW
          • DOWNLOAD
          • CHECK
          • KEEP.(SAME|MY)
          • VERIFY
          • ACCESS\\b
          • SIGN\\b
          • ENABLE\\b
          • RETAIN
          • PLAY
          • LISTEN
        • .display_text matches '^[^a-z]*[A-Z][^a-z]*$'
      • .display_text in ('Open')
      • all of:
        • .display_text contains 'go to documents'
        • any of recipients.to where:
          • strings.contains(body.current_thread.text)
      • .href_url.fragment in map(recipients.to, .email.email)
    • all of:
      • length(html.xpath(body.html, '//a//img[(number(@width) > 5 or not(@width)) and (number(@height) > 5 or not(@height))]').nodes) is 1
      • length(body.current_thread.text) < 500
    • all of:
      • length(attachments) > 0
      • any of attachments where any holds:
        • beta.ocr(.).text matches any of 15 patterns
          • activate
          • re-auth
          • verify
          • acknowledg
          • (keep|change).{0,20}(active|password|access)
          • ((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)
          • use.same.pass
          • validate.{0,15}account
          • recover.{0,15}messages
          • (retry|update).{0,10}payment
          • check activity
          • (listen|play).{0,10}(vm|voice)
          • clarify.{0,20}(deposit|wallet|funds)
          • enter.{0,15}teams
          • Review and sign
        • any of file.explode(.) where:
          • .scan.ocr.raw matches any of 15 patterns
            • activate
            • re-auth
            • verify
            • acknowledg
            • (keep|change).{0,20}(active|password|access)
            • ((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)
            • use.same.pass
            • validate.{0,15}account
            • recover.{0,15}messages
            • (retry|update).{0,10}payment
            • check activity
            • (listen|play).{0,10}(vm|voice)
            • clarify.{0,20}(deposit|wallet|funds)
            • enter.{0,15}teams
            • Review and sign
  5. any of:
    • not:
      • profile.by_sender_email().solicited
    • profile.by_sender_email().prevalence is 'new'
    • all of:
      • profile.by_sender_email().any_messages_malicious_or_spam
      • not:
        • profile.by_sender_email().any_messages_benign
    • all of:
      • profile.by_sender_email().any_messages_malicious_or_spam
      • profile.by_sender_email().any_messages_benign
      • any of:
        • not:
          • headers.auth_summary.dmarc.pass
        • not:
          • headers.auth_summary.spf.pass
  6. none of:
    • length(headers.references) > 0
    • headers.in_reply_to is set
  7. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • any of distinct(headers.hops) where:
        • .authentication_results.dmarc matches '*fail'
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains

Inspects: body.current_thread.text, body.html, body.html.inner_text, body.html.raw, body.links, body.links[].display_text, body.links[].href_url.fragment, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.hops, headers.hops[].authentication_results.dmarc, headers.in_reply_to, headers.references, mailbox.display_name, recipients.to, recipients.to[].email.email, recipients.to[].email.local_part, sender.display_name, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.ocr, file.explode, html.xpath, profile.by_sender_email, regex.contains, regex.count, regex.icontains, regex.match, strings.concat, strings.contains, strings.count, strings.icontains, strings.icount, strings.ilike, strings.replace_confusables. Reference lists: $high_trust_sender_root_domains.

Indicators matched (112)

FieldMatchValue
regex.icontainsregexD[0o]cuLink
regex.icontainsregexAgreement
regex.icontainsregexAccess.&.Appr[0o]ved
regex.icontainsregexAgreement.{0,5}Review
regex.icontainsregexAttend.and.Review
regex.icontainsregexaction.re?quired
regex.icontainsregexAuthentiSign
regex.icontainsregexCompleted.File
regex.icontainsregexD[0o]chsared
regex.icontainsregexD[0o]cshared
regex.icontainsregexD[0o]csPoint
regex.icontainsregexD[0o]cument.Shared
100 more
regex.icontainsregexD[0o]cuCentre
regex.icontainsregexD[0o]cuCenter
regex.icontainsregexD[0o]cCenter
regex.icontainsregexD[0o]csOnline
regex.icontainsregexD[0o]cSend
regex.icontainsregexD[0o]cu?Send
regex.icontainsregexd[0o]csign
regex.icontainsregexD[0o]cu-eSin
regex.icontainsregexD[0o]cu-management
regex.icontainsregex\\beSign
regex.icontainsregexe\\.sign
regex.icontainsregexesign.[0o]nline
regex.icontainsregex[SsZz][lL][GgSs][Nn].*D[0o]c
regex.icontainsregexe-d[0o]c
regex.icontainsregexe-signature
regex.icontainsregexe-Verify Doc
regex.icontainsregexeSignature
regex.icontainsregexeSign&Return
regex.icontainsregexeSign[0o]nline
regex.icontainsregexFileshare
regex.icontainsregexReview.and.C[0o]mplete
regex.icontainsregexReview.&.Sign
regex.icontainsregexSign[0o]nline
regex.icontainsregexSignature.Request
regex.icontainsregexShared.C[0o]mpleted
regex.icontainsregexSign.and.Seal
regex.icontainsregexviaSign
regex.icontainsregexD[0o]cuSign
regex.icontainsregexD[0o]csID
regex.icontainsregexComplete.{0,10}D[0o]cuSign
regex.icontainsregexEnroll & Sign
regex.icontainsregexReview and Sign
regex.icontainsregexSign(?:Report|Now)
regex.icontainsregexSignD[0o]c
regex.icontainsregexD[0o]cxxx
regex.icontainsregexd[0o]cufile
regex.icontainsregexE\x{00AD}-\x{00AD}S\x{00AD}i\x{00AD}g\x{00AD}n\x{00AD}&Return
regex.icontainsregexd[0o]cument.signature
regex.icontainsregexElectr[0o]nic.?Signature
regex.icontainsregexComplete:
regex.icontainsregexPlease (?:Review|Sign)
regex.icontainsregex^REVIEW$
regex.icontainsregexrequests your signature
regex.icontainsregexsignature on.*contract
regex.icontainsregexIndependent Contract
regex.icontainsregexContract.*signature
regex.icontainsregexadd your signature
regex.icontainsregexsignature needed
regex.icontainsregexattn_task
regex.icontainsregexDocReq\\b
regex.icontainsregex((<br\s*/?>\s*){20,}|\n{20,})
regex.icontainsregex(<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}
regex.icontainsregex(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\s*){30,}
regex.icontainsregex(<p>&nbsp;</p>\s*){7,}
regex.icontainsregex(<p[^>]*>\s*&nbsp;<br>\s*</p>\s*){5,}
regex.icontainsregex(<p[^>]*>&nbsp;</p>\s*){7,}
regex.countregex<span\s*class\s*=\s*"[^\"]+"\s*>\s*[a-z]\s*<\/span><span\s*class\s*=\s*"[^\"]+"\s*>\s*[a-z]+\s*<\/span>
regex.icontainsregex>Docus[1l]gn<
strings.icontainssubstringcompleted by all parties
regex.icontainsregexDocument
regex.countregexmailto:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}
regex.countregex<(?:p|div|span|td)[^>]*>\s*(?:&nbsp;|\s)*\s*</(?:p|div|span|td)>
strings.ilikesubstringHR
strings.ilikesubstringH?R
strings.ilikesubstring*Human Resources*
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregexactivate
regex.icontainsregexre-auth
regex.icontainsregexverify
regex.icontainsregexacknowledg
regex.icontainsregex(keep|change).{0,20}(active|password|access)
regex.icontainsregex((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)
regex.icontainsregexuse.same.pass
regex.icontainsregexvalidate.{0,15}account
regex.icontainsregexrecover.{0,15}messages
regex.icontainsregex(retry|update).{0,10}payment
regex.icontainsregexcheck activity
regex.icontainsregex(listen|play).{0,10}(vm|voice)
regex.icontainsregexclarify.{0,20}(deposit|wallet|funds)
regex.icontainsregexenter.{0,15}teams
regex.icontainsregexReview and sign
regex.icontainsregexREVIEW.*DOCUMENT
regex.icontainsregexOpen Document
regex.icontainsregexSign Now
regex.icontainsregexcomplete tasks?
regex.containsregex\\bVIEW
regex.containsregexDOWNLOAD
regex.containsregexCHECK
regex.containsregexKEEP.(SAME|MY)
regex.containsregexVERIFY
regex.containsregexACCESS\\b
regex.containsregexSIGN\\b
regex.containsregexENABLE\\b
regex.containsregexRETAIN
regex.containsregexPLAY
regex.containsregexLISTEN
regex.matchregex^[^a-z]*[A-Z][^a-z]*$
body.links[].display_textmemberOpen
strings.icontainssubstringgo to documents
strings.ilikesubstring*fail

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(attachments)
        or
          any(file.explode(attachments))
            or
              file.explode(attachments[])[].scan.ocr.raw regex_match "((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)"
              file.explode(attachments[])[].scan.ocr.raw regex_match "(keep|change).{0,20}(active|password|access)"
              file.explode(attachments[])[].scan.ocr.raw regex_match "(listen|play).{0,10}(vm|voice)"
              file.explode(attachments[])[].scan.ocr.raw regex_match "(retry|update).{0,10}payment"
              file.explode(attachments[])[].scan.ocr.raw regex_match "Review and sign"
              file.explode(attachments[])[].scan.ocr.raw regex_match "acknowledg"
              file.explode(attachments[])[].scan.ocr.raw regex_match "activate"
              file.explode(attachments[])[].scan.ocr.raw regex_match "check activity"
              file.explode(attachments[])[].scan.ocr.raw regex_match "clarify.{0,20}(deposit|wallet|funds)"
              file.explode(attachments[])[].scan.ocr.raw regex_match "enter.{0,15}teams"
              file.explode(attachments[])[].scan.ocr.raw regex_match "re-auth"
              file.explode(attachments[])[].scan.ocr.raw regex_match "recover.{0,15}messages"
              file.explode(attachments[])[].scan.ocr.raw regex_match "use.same.pass"
              file.explode(attachments[])[].scan.ocr.raw regex_match "validate.{0,15}account"
              file.explode(attachments[])[].scan.ocr.raw regex_match "verify"
          beta.ocr(attachments[]).text regex_match "((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)"
          beta.ocr(attachments[]).text regex_match "(keep|change).{0,20}(active|password|access)"
          beta.ocr(attachments[]).text regex_match "(listen|play).{0,10}(vm|voice)"
          beta.ocr(attachments[]).text regex_match "(retry|update).{0,10}payment"
          beta.ocr(attachments[]).text regex_match "Review and sign"
          beta.ocr(attachments[]).text regex_match "acknowledg"
          beta.ocr(attachments[]).text regex_match "activate"
          beta.ocr(attachments[]).text regex_match "check activity"
          beta.ocr(attachments[]).text regex_match "clarify.{0,20}(deposit|wallet|funds)"
          beta.ocr(attachments[]).text regex_match "enter.{0,15}teams"
          beta.ocr(attachments[]).text regex_match "re-auth"
          beta.ocr(attachments[]).text regex_match "recover.{0,15}messages"
          beta.ocr(attachments[]).text regex_match "use.same.pass"
          beta.ocr(attachments[]).text regex_match "validate.{0,15}account"
          beta.ocr(attachments[]).text regex_match "verify"
      attachments length_compare "0"
    any(body.links)
      or
        and
          or
            body.links.display_text regex_match "ACCESS\\\\b"
            body.links.display_text regex_match "CHECK"
            body.links.display_text regex_match "DOWNLOAD"
            body.links.display_text regex_match "ENABLE\\\\b"
            body.links.display_text regex_match "KEEP.(SAME|MY)"
            body.links.display_text regex_match "LISTEN"
            body.links.display_text regex_match "PLAY"
            body.links.display_text regex_match "RETAIN"
            body.links.display_text regex_match "SIGN\\\\b"
            body.links.display_text regex_match "VERIFY"
            body.links.display_text regex_match "\\\\bVIEW"
          body.links.display_text regex_match "^[^a-z]*[A-Z][^a-z]*$"
        and
          any(recipients.to)
            strings.contains func_call "strings.contains(body.current_thread.text)"
          body.links.display_text contains "go to documents"
        body.links.display_text eq "Open"
        strings.replace_confusables(body.links[].display_text) regex_match "((verify|view|click|download|goto|keep|Vιew|release).{0,15}(attachment|current|download|fax|file|document|message|same)s?)"
        strings.replace_confusables(body.links[].display_text) regex_match "(keep|change).{0,20}(active|password|access)"
        strings.replace_confusables(body.links[].display_text) regex_match "(listen|play).{0,10}(vm|voice)"
        strings.replace_confusables(body.links[].display_text) regex_match "(retry|update).{0,10}payment"
        strings.replace_confusables(body.links[].display_text) regex_match "Open Document"
        strings.replace_confusables(body.links[].display_text) regex_match "REVIEW.*DOCUMENT"
        strings.replace_confusables(body.links[].display_text) regex_match "Review and sign"
        strings.replace_confusables(body.links[].display_text) regex_match "Sign Now"
        strings.replace_confusables(body.links[].display_text) regex_match "acknowledg"
        strings.replace_confusables(body.links[].display_text) regex_match "activate"
        strings.replace_confusables(body.links[].display_text) regex_match "check activity"
        strings.replace_confusables(body.links[].display_text) regex_match "clarify.{0,20}(deposit|wallet|funds)"
        strings.replace_confusables(body.links[].display_text) regex_match "complete tasks?"
        strings.replace_confusables(body.links[].display_text) regex_match "enter.{0,15}teams"
        strings.replace_confusables(body.links[].display_text) regex_match "re-auth"
        strings.replace_confusables(body.links[].display_text) regex_match "recover.{0,15}messages"
        strings.replace_confusables(body.links[].display_text) regex_match "use.same.pass"
        strings.replace_confusables(body.links[].display_text) regex_match "validate.{0,15}account"
        strings.replace_confusables(body.links[].display_text) regex_match "verify"
         macro "body.links[].href_url.fragment in map(recipients.to, body.links[].email.email)"
    and
      body.current_thread.text length_compare "500"
      html.xpath(body.html, '//a//img[(number(@width) > 5 or not(@width)) and (number(@height) > 5 or not(@height))]').nodes length_compare "1"
  any([subject.subject, sender.display_name])
    or
      and
        not
          and
            headers.auth_summary.dmarc.pass eq "true"
            sender.email.domain.root_domain eq "sharepointonline.com"
            subject.subject contains "asked to edit"
        strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "action.re?quired"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Access.&.Appr[0o]ved"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Agreement"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Agreement.{0,5}Review"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Attend.and.Review"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "AuthentiSign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Complete.{0,10}D[0o]cuSign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Complete: "
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Completed.File"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Contract.*signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cCenter"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cSend"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]chsared"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]csID"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]csOnline"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]csPoint"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cshared"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cu-eSin"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cu-management"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cu?Send"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cuCenter"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cuCentre"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cuLink"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cuSign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cument.Shared"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "D[0o]cxxx"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "DocReq\\\\b"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "E\\x{00AD}-\\x{00AD}S\\x{00AD}i\\x{00AD}g\\x{00AD}n\\x{00AD}&Return"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Electr[0o]nic.?Signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Enroll & Sign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Fileshare"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Independent Contract"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Please (?:Review|Sign)"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Review and Sign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Review.&.Sign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Review.and.C[0o]mplete"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Shared.C[0o]mpleted"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Sign(?:Report|Now)"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Sign.and.Seal"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "SignD[0o]c"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Sign[0o]nline"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "Signature.Request"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "[SsZz][lL][GgSs][Nn].*D[0o]c"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "\\\\beSign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "^REVIEW$"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "action.re?quired"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "add your signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "attn_task"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "d[0o]csign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "d[0o]cufile"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "d[0o]cument.signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "e-Verify Doc"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "e-d[0o]c"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "e-signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "eSign&Return"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "eSign[0o]nline"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "eSignature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "e\\\\.sign"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "esign.[0o]nline"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "requests your signature"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "signature needed"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "signature on.*contract"
      strings.replace_confusables([subject.subject, sender.display_name][]) regex_match "viaSign"
  or
    and
      or
        not
          headers.auth_summary.dmarc.pass eq "true"
        not
          headers.auth_summary.spf.pass eq "true"
      profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
      profile.by_sender_email func_call "profile.by_sender_email().any_messages_malicious_or_spam"
    and
      not
        profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
      profile.by_sender_email func_call "profile.by_sender_email().any_messages_malicious_or_spam"
    not
      profile.by_sender_email func_call "profile.by_sender_email().solicited"
    profile.by_sender_email func_call "profile.by_sender_email().prevalence == new"
  or
    and
      any(distinct(headers.hops))
        distinct(headers.hops).authentication_results.dmarc ends_with "fail"
       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
      body.html.inner_text length_compare "500"
      body.html.inner_text regex_match "Document"
    any(recipients.to)
      strings.icount func_call "strings.icount(body.current_thread.text) > sum([strings.icount(body.current_thread.text, strings.concat('was sent to ', recipients.to[].email.email)), strings.icount(body.current_thread.text, strings.concat('intended for ', recipients.to[].email.email))])"
    body.current_thread.text contains "completed by all parties"
    body.html.raw regex_match "((<br\\s*/?>\\s*){20,}|\\n{20,})"
    body.html.raw regex_match "(<p class=\".*?\"><span style=\".*?\"><o:p>&nbsp;</o:p></span></p>\\s*){30,}"
    body.html.raw regex_match "(<p>&nbsp;</p>\\s*){7,}"
    body.html.raw regex_match "(<p[^>]*>&nbsp;</p>\\s*){7,}"
    body.html.raw regex_match "(<p[^>]*>\\s*&nbsp;<br>\\s*</p>\\s*){5,}"
    body.html.raw regex_match "(<p[^>]*>\\s*<br\\s*/?>\\s*</p>\\s*){30,}"
    body.html.raw regex_match ">Docus[1l]gn<"
    regex.count func_call "regex.count(body.html.raw, \"<(?:p|div|span|td)[^>]*>\\s*(?:&nbsp;|\\s)*\\s*</(?:p|div|span|td)>\") > 30"
    regex.count func_call "regex.count(body.html.raw, \"<span\\s*class\\s*=\\s*\"[^\\\"]+\"\\s*>\\s*[a-z]\\s*<\\/span><span\\s*class\\s*=\\s*\"[^\\\"]+\"\\s*>\\s*[a-z]+\\s*<\\/span>\") > 50"
    regex.count func_call "regex.count(body.html.raw, \"mailto:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\") > 50"
    sender.display_name eq "H?R"
    sender.display_name eq "HR"
    sender.display_name match "Human Resources"
    sender.display_name regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
    strings.count func_call "strings.count(body.html.raw, \"&nbsp;\\u{200C}&nbsp;\\u{200C}&nbsp\") > 50"
    strings.icount func_call "strings.icount(body.current_thread.text) > sum([strings.icount(body.current_thread.text, strings.concat('was sent to ', mailbox.display_name)), strings.icount(body.current_thread.text, strings.concat('intended for ', mailbox.display_name))])"
  not
    or
      headers.in_reply_to is_not_null
      headers.references length_compare "0"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • completed by all parties
field:"body.current_thread.text" kind:contains value:"completed by all parties"
body.html.inner_textregex_match
  • Document
field:"body.html.inner_text" kind:regex_match value:"Document"
body.html.rawregex_match
  • ((<br\s*/?>\s*){20,}|\n{20,})
  • (<p class=".*?"><span style=".*?"><o:p> </o:p></span></p>\s*){30,}
  • (<p> </p>\s*){7,}
  • (<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}
  • (<p[^>]*>\s* <br>\s*</p>\s*){5,}
  • (<p[^>]*> </p>\s*){7,}
  • >Docus[1l]gn<
field:"body.html.raw" kind:regex_match
sender.display_nameregex_match
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"sender.display_name" kind:regex_match value:"+?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}"
sender.display_namewildcard
  • *Human Resources*
  • H?R
  • HR
field:"sender.display_name" kind:wildcard
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Suspicious subject with urgent financial request and link

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

This rule inspects messages where the subject is suspicious with less than 5 links and a relatively short body. Natural Language Understanding is being used to identify the inclusion of a financial, request, urgency and org entity from an unsolicited sender.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and (
  0 < length(filter(body.links,
                    not strings.ilike(.display_text,
                                      "*privacy*",
                                      "*terms of service*",
                                      "Learn why this is important"
                    )
                    or .display_text is null
             )
  ) < 5
)

// negate webinar registrations
and not any(body.links,
            .display_text =~ "REGISTER NOW"
            and .href_url.domain.root_domain == "secureclick.net"
)

// not all links are unsubscribe links
and not all(body.links,
            (
              strings.icontains(.display_text, "unsubscribe")
              and strings.icontains(.href_url.path, "unsubscribe")
            )
            or (
              strings.icontains(.display_text, "deactivate")
              and strings.icontains(.href_url.path, "DeactivateAccount")
            )
)

// ignore emails in body
and not all(body.links, .href_url.domain.domain in $free_email_providers)
and length(body.current_thread.text) < 2000
and length(subject.subject) < 100

// and suspicious subject
and regex.icontains(subject.subject,
                    // https://github.com/sublime-security/static-files/blob/main/suspicious_subjects_regex.txt
                    "termination.*notice",
                    "38417",
                    ":completed",
                    "[il1]{2}mit.*ma[il1]{2} ?bo?x",
                    "[il][il][il]egai[ -]",
                    "[li][li][li]ega[li] attempt",
                    "[ng]-?[io]n .*block",
                    "[ng]-?[io]n .*cancel",
                    "[ng]-?[io]n .*deactiv",
                    "[ng]-?[io]n .*disabl",
                    "action.*required",
                    "abandon.*package",
                    "about.your.account",
                    "acc(ou)?n?t (is )?on ho[li]d",
                    "acc(ou)?n?t.*terminat",
                    "acc(oun)?t.*[il1]{2}mitation",
                    "access.*limitation",
                    "account (will be )?block",
                    "account.*de-?activat",
                    "account.*locked",
                    "account.*re-verification",
                    "account.*security",
                    "account.*suspension",
                    "account.has.been",
                    "account.has.expired",
                    "account.will.be.blocked",
                    "account v[il]o[li]at",
                    "activity.*acc(oun)?t",
                    "almost.full",
                    "app[li]e.[il]d",
                    "authenticate.*account",
                    "been.*suspend",
                    "clos.*of.*account.*processed",
                    "confirm.your.account",
                    "courier.*able",
                    "crediential.*notif",
                    "deactivation.*in.*progress",
                    "delivery.*attempt.*failed",
                    "document.(?:submitted|received)",
                    "documented.*shared.*with.*you",
                    "dropbox.*document",
                    "e-?ma[il1]+ .{010}suspen",
                    "e-?ma[il1]{1} user",
                    "e-?ma[il1]{2} acc",
                    "e-?ma[il1]{2}.*up.?grade",
                    "e.?ma[il1]{2}.*server",
                    "e.?ma[il1]{2}.*suspend",
                    "email.update",
                    "faxed you",
                    "^final reminder: .*(?:overdue|resolve|access ends)",
                    "fraud(ulent)?.*charge",
                    "from.helpdesk",
                    "fu[il1]{2}.*ma[il1]+[ -]?box",
                    "has.been.*suspended",
                    "has.been.limited",
                    "have.locked",
                    "he[li]p ?desk upgrade",
                    "heipdesk",
                    "i[il]iega[il]",
                    "ii[il]ega[il]",
                    "incoming e?mail",
                    "incoming.*fax",
                    "lock.*security",
                    "ma[il1]{1}[ -]?box.*quo",
                    "ma[il1]{2}[ -]?box.*fu[il1]",
                    "ma[il1]{2}box.*[il1]{2}mit",
                    "ma[il1]{2}box stor",
                    "mail on.?hold",
                    "mail.*box.*migration",
                    "mail.*de-?activat",
                    "mail.update.required",
                    "mails.*pending",
                    "messages.*pending",
                    "missed.*shipping.*notification",
                    "missed.shipment.notification",
                    "must.update.your.account",
                    "new [sl][io]g?[nig][ -]?in from",
                    "new voice ?-?mail",
                    "notifications.*pending",
                    "office.*3.*6.*5.*suspend",
                    "office365",
                    "on google docs with you",
                    "online doc",
                    "password.*compromised",
                    "periodic maintenance",
                    "potential(ly)? unauthorized",
                    "refund not approved",
                    "revised.*policy",
                    "scam",
                    "scanned.?invoice",
                    "secured?.update",
                    "security breach",
                    "securlty",
                    "signed.*delivery",
                    "status of your .{314}? ?delivery",
                    "susp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty",
                    "suspicious.*sign.*[io]n",
                    "suspicious.activit",
                    "temporar(il)?y deactivate",
                    "temporar[il1]{2}y disab[li]ed",
                    "temporarily.*lock",
                    "un-?usua[li].activity",
                    "unable.*deliver",
                    "unauthorized.*activit",
                    "unauthorized.device",
                    "unauthorized.sign.?in",
                    "unrecognized.*activit",
                    "unrecognized.sign.?in",
                    "unrecognized.*activit",
                    "undelivered message",
                    "unread.*doc",
                    "unusual.activity",
                    "upgrade.*account",
                    "upgrade.notice",
                    "urgent message",
                    "urgent.verification",
                    "v[il1]o[li1]at[il1]on security",
                    "va[il1]{1}date.*ma[il1]{2}[ -]?box",
                    "verification ?-?require",
                    "verification( )?-?need",
                    "verify.your?.account",
                    "web ?-?ma[il1]{2}",
                    "web[ -]?ma[il1]{2}",
                    "will.be.suspended",
                    "your (customer )?account .as",
                    "your.office.365",
                    "your.online.access",

                    // https://github.com/sublime-security/static-files/blob/main/suspicious_subjects.txt
                    "account has been limited",
                    "action required",
                    "almost full",
                    "apd notifi cation",
                    "are you at your desk",
                    "are you available",
                    "attached file to docusign",
                    "banking is temporarily unavailable",
                    "bankofamerica",
                    "closing statement invoice",
                    "completed: docusign",
                    "de-activation of",
                    "delivery attempt",
                    "delivery stopped for shipment",
                    "detected suspicious",
                    "detected suspicious actvity",
                    "docu sign",
                    "document for you",
                    "document has been sent to you via docusign",
                    "document is ready for signature",
                    "docusign",
                    "encrypted message",
                    "failed delivery",
                    "fedex tracking",
                    "file was shared",
                    "freefax",
                    "fwd: due invoice paid",
                    "has shared",
                    "inbox is full",
                    "invitation to comment",
                    "invitation to edit",
                    "invoice due",
                    "left you a message",
                    "message from",
                    "new message",
                    "new voicemail",
                    "on desk",
                    "out of space",
                    "password reset",
                    "payment status",
                    "quick reply",
                    "re: w-2",
                    "required",
                    "required: completed docusign",
                    "ringcentral",
                    "scanned image",
                    "secured files",
                    "secured pdf",
                    "security alert",
                    "new sign-in",
                    "new sign in",
                    "sign-in attempt",
                    "sign in attempt",
                    "staff review",
                    "suspicious activity",
                    "unrecognized login attempt",
                    "upgrade immediately",
                    "urgent",
                    "wants to share",
                    '\bw2\b',
                    "you have notifications pending",
                    "your account",
                    "your amazon order",
                    "your document settlement",
                    "your order with amazon",
                    "your password has been compromised",

                    // cryptocurrency related subjects
                    '\d{1,2}.\d{1,8}\s(BTC|ETH|SOL|(?:USD[CT])|XRP) Offer Waiting for(\sYour)?\sReview',
)

// language attempting to engage
and any(ml.nlu_classifier(body.current_thread.text).entities,
        .name == "request"
)

// financial request
and any(ml.nlu_classifier(body.current_thread.text).entities,
        .name == "financial"
)

// urgency request
and any(ml.nlu_classifier(body.current_thread.text).entities,
        .name == "urgency"
)

// org presence
and any(ml.nlu_classifier(body.current_thread.text).entities, .name == "org")

// not a reply
and (
  not strings.istarts_with(subject.subject, "re:")
  and headers.in_reply_to is null
)

// the message is unsolicited and no false positives
and (
  not profile.by_sender_email().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and profile.by_sender().any_messages_benign
    and (
      not headers.auth_summary.dmarc.pass or not headers.auth_summary.spf.pass
    )
  )
)

// 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
)

// negation the only link is the senders email
and not (
  regex.contains(body.current_thread.text,
                 "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
  )
  and (
    all(body.links, .href_url.domain.root_domain == sender.email.domain.domain)
  )
)

Detection logic

Scope: inbound message.

This rule inspects messages where the subject is suspicious with less than 5 links and a relatively short body. Natural Language Understanding is being used to identify the inclusion of a financial, request, urgency and org entity from an unsolicited sender.

  1. inbound message
  2. all of:
    • length(filter(body.links, not strings.ilike(.display_text, '*privacy*', '*terms of service*', 'Learn why this is important') or .display_text is null)) > 0
    • length(filter(body.links, not strings.ilike(.display_text, '*privacy*', '*terms of service*', 'Learn why this is important') or .display_text is null)) < 5
  3. not:
    • any of body.links where all hold:
      • .display_text is 'REGISTER NOW'
      • .href_url.domain.root_domain is 'secureclick.net'
  4. not:
    • all of body.links where any holds:
      • all of:
        • .display_text contains 'unsubscribe'
        • .href_url.path contains 'unsubscribe'
      • all of:
        • .display_text contains 'deactivate'
        • .href_url.path contains 'DeactivateAccount'
  5. not:
    • all of body.links where:
      • .href_url.domain.domain in $free_email_providers
  6. length(body.current_thread.text) < 2000
  7. length(subject.subject) < 100
  8. subject.subject matches any of 194 patterns
    • termination.*notice
    • 38417
    • :completed
    • [il1]{2}mit.*ma[il1]{2} ?bo?x
    • [il][il][il]egai[ -]
    • [li][li][li]ega[li] attempt
    • [ng]-?[io]n .*block
    • [ng]-?[io]n .*cancel
    • [ng]-?[io]n .*deactiv
    • [ng]-?[io]n .*disabl
    • action.*required
    • abandon.*package
    • about.your.account
    • acc(ou)?n?t (is )?on ho[li]d
    • acc(ou)?n?t.*terminat
    • acc(oun)?t.*[il1]{2}mitation
    • access.*limitation
    • account (will be )?block
    • account.*de-?activat
    • account.*locked
    • account.*re-verification
    • account.*security
    • account.*suspension
    • account.has.been
    • account.has.expired
    • account.will.be.blocked
    • account v[il]o[li]at
    • activity.*acc(oun)?t
    • almost.full
    • app[li]e.[il]d
    • authenticate.*account
    • been.*suspend
    • clos.*of.*account.*processed
    • confirm.your.account
    • courier.*able
    • crediential.*notif
    • deactivation.*in.*progress
    • delivery.*attempt.*failed
    • document.(?:submitted|received)
    • documented.*shared.*with.*you
    • dropbox.*document
    • e-?ma[il1]+ .{010}suspen
    • e-?ma[il1]{1} user
    • e-?ma[il1]{2} acc
    • e-?ma[il1]{2}.*up.?grade
    • e.?ma[il1]{2}.*server
    • e.?ma[il1]{2}.*suspend
    • email.update
    • faxed you
    • ^final reminder: .*(?:overdue|resolve|access ends)
    • fraud(ulent)?.*charge
    • from.helpdesk
    • fu[il1]{2}.*ma[il1]+[ -]?box
    • has.been.*suspended
    • has.been.limited
    • have.locked
    • he[li]p ?desk upgrade
    • heipdesk
    • i[il]iega[il]
    • ii[il]ega[il]
    • incoming e?mail
    • incoming.*fax
    • lock.*security
    • ma[il1]{1}[ -]?box.*quo
    • ma[il1]{2}[ -]?box.*fu[il1]
    • ma[il1]{2}box.*[il1]{2}mit
    • ma[il1]{2}box stor
    • mail on.?hold
    • mail.*box.*migration
    • mail.*de-?activat
    • mail.update.required
    • mails.*pending
    • messages.*pending
    • missed.*shipping.*notification
    • missed.shipment.notification
    • must.update.your.account
    • new [sl][io]g?[nig][ -]?in from
    • new voice ?-?mail
    • notifications.*pending
    • office.*3.*6.*5.*suspend
    • office365
    • on google docs with you
    • online doc
    • password.*compromised
    • periodic maintenance
    • potential(ly)? unauthorized
    • refund not approved
    • revised.*policy
    • scam
    • scanned.?invoice
    • secured?.update
    • security breach
    • securlty
    • signed.*delivery
    • status of your .{314}? ?delivery
    • susp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty
    • suspicious.*sign.*[io]n
    • suspicious.activit
    • temporar(il)?y deactivate
    • temporar[il1]{2}y disab[li]ed
    • temporarily.*lock
    • un-?usua[li].activity
    • unable.*deliver
    • unauthorized.*activit
    • unauthorized.device
    • unauthorized.sign.?in
    • unrecognized.*activit
    • unrecognized.sign.?in
    • unrecognized.*activit
    • undelivered message
    • unread.*doc
    • unusual.activity
    • upgrade.*account
    • upgrade.notice
    • urgent message
    • urgent.verification
    • v[il1]o[li1]at[il1]on security
    • va[il1]{1}date.*ma[il1]{2}[ -]?box
    • verification ?-?require
    • verification( )?-?need
    • verify.your?.account
    • web ?-?ma[il1]{2}
    • web[ -]?ma[il1]{2}
    • will.be.suspended
    • your (customer )?account .as
    • your.office.365
    • your.online.access
    • account has been limited
    • action required
    • almost full
    • apd notifi cation
    • are you at your desk
    • are you available
    • attached file to docusign
    • banking is temporarily unavailable
    • bankofamerica
    • closing statement invoice
    • completed: docusign
    • de-activation of
    • delivery attempt
    • delivery stopped for shipment
    • detected suspicious
    • detected suspicious actvity
    • docu sign
    • document for you
    • document has been sent to you via docusign
    • document is ready for signature
    • docusign
    • encrypted message
    • failed delivery
    • fedex tracking
    • file was shared
    • freefax
    • fwd: due invoice paid
    • has shared
    • inbox is full
    • invitation to comment
    • invitation to edit
    • invoice due
    • left you a message
    • message from
    • new message
    • new voicemail
    • on desk
    • out of space
    • password reset
    • payment status
    • quick reply
    • re: w-2
    • required
    • required: completed docusign
    • ringcentral
    • scanned image
    • secured files
    • secured pdf
    • security alert
    • new sign-in
    • new sign in
    • sign-in attempt
    • sign in attempt
    • staff review
    • suspicious activity
    • unrecognized login attempt
    • upgrade immediately
    • urgent
    • wants to share
    • \bw2\b
    • you have notifications pending
    • your account
    • your amazon order
    • your document settlement
    • your order with amazon
    • your password has been compromised
    • \d{1,2}.\d{1,8}\s(BTC|ETH|SOL|(?:USD[CT])|XRP) Offer Waiting for(\sYour)?\sReview
  9. any of ml.nlu_classifier(body.current_thread.text).entities where:
    • .name is 'request'
  10. any of ml.nlu_classifier(body.current_thread.text).entities where:
    • .name is 'financial'
  11. any of ml.nlu_classifier(body.current_thread.text).entities where:
    • .name is 'urgency'
  12. any of ml.nlu_classifier(body.current_thread.text).entities where:
    • .name is 'org'
  13. all of:
    • not:
      • subject.subject starts with 're:'
    • headers.in_reply_to is missing
  14. any of:
    • not:
      • profile.by_sender_email().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • profile.by_sender().any_messages_benign
      • any of:
        • not:
          • headers.auth_summary.dmarc.pass
        • not:
          • headers.auth_summary.spf.pass
  15. 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
  16. not:
    • all of:
      • body.current_thread.text matches '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}'
      • all of body.links where:
        • .href_url.domain.root_domain is sender.email.domain.domain

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.links[].href_url.path, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.in_reply_to, sender.email.domain.domain, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, profile.by_sender_email, regex.contains, regex.icontains, strings.icontains, strings.ilike, strings.istarts_with. Reference lists: $free_email_providers, $high_trust_sender_root_domains.

Indicators matched (197)

FieldMatchValue
regex.icontainsregextermination.*notice
regex.icontainsregex38417
regex.icontainsregex:completed
regex.icontainsregex[il1]{2}mit.*ma[il1]{2} ?bo?x
regex.icontainsregex[il][il][il]egai[ -]
regex.icontainsregex[li][li][li]ega[li] attempt
regex.icontainsregex[ng]-?[io]n .*block
regex.icontainsregex[ng]-?[io]n .*cancel
regex.icontainsregex[ng]-?[io]n .*deactiv
regex.icontainsregex[ng]-?[io]n .*disabl
regex.icontainsregexaction.*required
regex.icontainsregexabandon.*package
185 more
regex.icontainsregexabout.your.account
regex.icontainsregexacc(ou)?n?t (is )?on ho[li]d
regex.icontainsregexacc(ou)?n?t.*terminat
regex.icontainsregexacc(oun)?t.*[il1]{2}mitation
regex.icontainsregexaccess.*limitation
regex.icontainsregexaccount (will be )?block
regex.icontainsregexaccount.*de-?activat
regex.icontainsregexaccount.*locked
regex.icontainsregexaccount.*re-verification
regex.icontainsregexaccount.*security
regex.icontainsregexaccount.*suspension
regex.icontainsregexaccount.has.been
regex.icontainsregexaccount.has.expired
regex.icontainsregexaccount.will.be.blocked
regex.icontainsregexaccount v[il]o[li]at
regex.icontainsregexactivity.*acc(oun)?t
regex.icontainsregexalmost.full
regex.icontainsregexapp[li]e.[il]d
regex.icontainsregexauthenticate.*account
regex.icontainsregexbeen.*suspend
regex.icontainsregexclos.*of.*account.*processed
regex.icontainsregexconfirm.your.account
regex.icontainsregexcourier.*able
regex.icontainsregexcrediential.*notif
regex.icontainsregexdeactivation.*in.*progress
regex.icontainsregexdelivery.*attempt.*failed
regex.icontainsregexdocument.(?:submitted|received)
regex.icontainsregexdocumented.*shared.*with.*you
regex.icontainsregexdropbox.*document
regex.icontainsregexe-?ma[il1]+ .{010}suspen
regex.icontainsregexe-?ma[il1]{1} user
regex.icontainsregexe-?ma[il1]{2} acc
regex.icontainsregexe-?ma[il1]{2}.*up.?grade
regex.icontainsregexe.?ma[il1]{2}.*server
regex.icontainsregexe.?ma[il1]{2}.*suspend
regex.icontainsregexemail.update
regex.icontainsregexfaxed you
regex.icontainsregex^final reminder: .*(?:overdue|resolve|access ends)
regex.icontainsregexfraud(ulent)?.*charge
regex.icontainsregexfrom.helpdesk
regex.icontainsregexfu[il1]{2}.*ma[il1]+[ -]?box
regex.icontainsregexhas.been.*suspended
regex.icontainsregexhas.been.limited
regex.icontainsregexhave.locked
regex.icontainsregexhe[li]p ?desk upgrade
regex.icontainsregexheipdesk
regex.icontainsregexi[il]iega[il]
regex.icontainsregexii[il]ega[il]
regex.icontainsregexincoming e?mail
regex.icontainsregexincoming.*fax
regex.icontainsregexlock.*security
regex.icontainsregexma[il1]{1}[ -]?box.*quo
regex.icontainsregexma[il1]{2}[ -]?box.*fu[il1]
regex.icontainsregexma[il1]{2}box.*[il1]{2}mit
regex.icontainsregexma[il1]{2}box stor
regex.icontainsregexmail on.?hold
regex.icontainsregexmail.*box.*migration
regex.icontainsregexmail.*de-?activat
regex.icontainsregexmail.update.required
regex.icontainsregexmails.*pending
regex.icontainsregexmessages.*pending
regex.icontainsregexmissed.*shipping.*notification
regex.icontainsregexmissed.shipment.notification
regex.icontainsregexmust.update.your.account
regex.icontainsregexnew [sl][io]g?[nig][ -]?in from
regex.icontainsregexnew voice ?-?mail
regex.icontainsregexnotifications.*pending
regex.icontainsregexoffice.*3.*6.*5.*suspend
regex.icontainsregexoffice365
regex.icontainsregexon google docs with you
regex.icontainsregexonline doc
regex.icontainsregexpassword.*compromised
regex.icontainsregexperiodic maintenance
regex.icontainsregexpotential(ly)? unauthorized
regex.icontainsregexrefund not approved
regex.icontainsregexrevised.*policy
regex.icontainsregexscam
regex.icontainsregexscanned.?invoice
regex.icontainsregexsecured?.update
regex.icontainsregexsecurity breach
regex.icontainsregexsecurlty
regex.icontainsregexsigned.*delivery
regex.icontainsregexstatus of your .{314}? ?delivery
regex.icontainsregexsusp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty
regex.icontainsregexsuspicious.*sign.*[io]n
regex.icontainsregexsuspicious.activit
regex.icontainsregextemporar(il)?y deactivate
regex.icontainsregextemporar[il1]{2}y disab[li]ed
regex.icontainsregextemporarily.*lock
regex.icontainsregexun-?usua[li].activity
regex.icontainsregexunable.*deliver
regex.icontainsregexunauthorized.*activit
regex.icontainsregexunauthorized.device
regex.icontainsregexunauthorized.sign.?in
regex.icontainsregexunrecognized.*activit
regex.icontainsregexunrecognized.sign.?in
regex.icontainsregexundelivered message
regex.icontainsregexunread.*doc
regex.icontainsregexunusual.activity
regex.icontainsregexupgrade.*account
regex.icontainsregexupgrade.notice
regex.icontainsregexurgent message
regex.icontainsregexurgent.verification
regex.icontainsregexv[il1]o[li1]at[il1]on security
regex.icontainsregexva[il1]{1}date.*ma[il1]{2}[ -]?box
regex.icontainsregexverification ?-?require
regex.icontainsregexverification( )?-?need
regex.icontainsregexverify.your?.account
regex.icontainsregexweb ?-?ma[il1]{2}
regex.icontainsregexweb[ -]?ma[il1]{2}
regex.icontainsregexwill.be.suspended
regex.icontainsregexyour (customer )?account .as
regex.icontainsregexyour.office.365
regex.icontainsregexyour.online.access
regex.icontainsregexaccount has been limited
regex.icontainsregexaction required
regex.icontainsregexalmost full
regex.icontainsregexapd notifi cation
regex.icontainsregexare you at your desk
regex.icontainsregexare you available
regex.icontainsregexattached file to docusign
regex.icontainsregexbanking is temporarily unavailable
regex.icontainsregexbankofamerica
regex.icontainsregexclosing statement invoice
regex.icontainsregexcompleted: docusign
regex.icontainsregexde-activation of
regex.icontainsregexdelivery attempt
regex.icontainsregexdelivery stopped for shipment
regex.icontainsregexdetected suspicious
regex.icontainsregexdetected suspicious actvity
regex.icontainsregexdocu sign
regex.icontainsregexdocument for you
regex.icontainsregexdocument has been sent to you via docusign
regex.icontainsregexdocument is ready for signature
regex.icontainsregexdocusign
regex.icontainsregexencrypted message
regex.icontainsregexfailed delivery
regex.icontainsregexfedex tracking
regex.icontainsregexfile was shared
regex.icontainsregexfreefax
regex.icontainsregexfwd: due invoice paid
regex.icontainsregexhas shared
regex.icontainsregexinbox is full
regex.icontainsregexinvitation to comment
regex.icontainsregexinvitation to edit
regex.icontainsregexinvoice due
regex.icontainsregexleft you a message
regex.icontainsregexmessage from
regex.icontainsregexnew message
regex.icontainsregexnew voicemail
regex.icontainsregexon desk
regex.icontainsregexout of space
regex.icontainsregexpassword reset
regex.icontainsregexpayment status
regex.icontainsregexquick reply
regex.icontainsregexre: w-2
regex.icontainsregexrequired
regex.icontainsregexrequired: completed docusign
regex.icontainsregexringcentral
regex.icontainsregexscanned image
regex.icontainsregexsecured files
regex.icontainsregexsecured pdf
regex.icontainsregexsecurity alert
regex.icontainsregexnew sign-in
regex.icontainsregexnew sign in
regex.icontainsregexsign-in attempt
regex.icontainsregexsign in attempt
regex.icontainsregexstaff review
regex.icontainsregexsuspicious activity
regex.icontainsregexunrecognized login attempt
regex.icontainsregexupgrade immediately
regex.icontainsregexurgent
regex.icontainsregexwants to share
regex.icontainsregex\bw2\b
regex.icontainsregexyou have notifications pending
regex.icontainsregexyour account
regex.icontainsregexyour amazon order
regex.icontainsregexyour document settlement
regex.icontainsregexyour order with amazon
regex.icontainsregexyour password has been compromised
regex.icontainsregex\d{1,2}.\d{1,8}\s(BTC|ETH|SOL|(?:USD[CT])|XRP) Offer Waiting for(\sYour)?\sReview
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsrequest
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsfinancial
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsurgency
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsorg

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        not
          headers.auth_summary.dmarc.pass eq "true"
        not
          headers.auth_summary.spf.pass eq "true"
      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().any_messages_benign"
      profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
    not
      profile.by_sender_email func_call "profile.by_sender_email().solicited"
  not
    any(body.links)
      and
        body.links.display_text eq "REGISTER NOW"
        body.links.href_url.domain.root_domain eq "secureclick.net"
  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"
  not
    and
      body.current_thread.text regex_match "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}"
       macro "all(body.links)"
  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 "org"
  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"
  or
    subject.subject regex_match "38417"
    subject.subject regex_match ":completed"
    subject.subject regex_match "[il1]{2}mit.*ma[il1]{2} ?bo?x"
    subject.subject regex_match "[il][il][il]egai[ -]"
    subject.subject regex_match "[li][li][li]ega[li] attempt"
    subject.subject regex_match "[ng]-?[io]n .*block"
    subject.subject regex_match "[ng]-?[io]n .*cancel"
    subject.subject regex_match "[ng]-?[io]n .*deactiv"
    subject.subject regex_match "[ng]-?[io]n .*disabl"
    subject.subject regex_match "\\bw2\\b"
    subject.subject regex_match "\\d{1,2}.\\d{1,8}\\s(BTC|ETH|SOL|(?:USD[CT])|XRP) Offer Waiting for(\\sYour)?\\sReview"
    subject.subject regex_match "^final reminder: .*(?:overdue|resolve|access ends)"
    subject.subject regex_match "abandon.*package"
    subject.subject regex_match "about.your.account"
    subject.subject regex_match "acc(ou)?n?t (is )?on ho[li]d"
    subject.subject regex_match "acc(ou)?n?t.*terminat"
    subject.subject regex_match "acc(oun)?t.*[il1]{2}mitation"
    subject.subject regex_match "access.*limitation"
    subject.subject regex_match "account (will be )?block"
    subject.subject regex_match "account has been limited"
    subject.subject regex_match "account v[il]o[li]at"
    subject.subject regex_match "account.*de-?activat"
    subject.subject regex_match "account.*locked"
    subject.subject regex_match "account.*re-verification"
    subject.subject regex_match "account.*security"
    subject.subject regex_match "account.*suspension"
    subject.subject regex_match "account.has.been"
    subject.subject regex_match "account.has.expired"
    subject.subject regex_match "account.will.be.blocked"
    subject.subject regex_match "action required"
    subject.subject regex_match "action.*required"
    subject.subject regex_match "activity.*acc(oun)?t"
    subject.subject regex_match "almost full"
    subject.subject regex_match "almost.full"
    subject.subject regex_match "apd notifi cation"
    subject.subject regex_match "app[li]e.[il]d"
    subject.subject regex_match "are you at your desk"
    subject.subject regex_match "are you available"
    subject.subject regex_match "attached file to docusign"
    subject.subject regex_match "authenticate.*account"
    subject.subject regex_match "banking is temporarily unavailable"
    subject.subject regex_match "bankofamerica"
    subject.subject regex_match "been.*suspend"
    subject.subject regex_match "clos.*of.*account.*processed"
    subject.subject regex_match "closing statement invoice"
    subject.subject regex_match "completed: docusign"
    subject.subject regex_match "confirm.your.account"
    subject.subject regex_match "courier.*able"
    subject.subject regex_match "crediential.*notif"
    subject.subject regex_match "de-activation of"
    subject.subject regex_match "deactivation.*in.*progress"
    subject.subject regex_match "delivery attempt"
    subject.subject regex_match "delivery stopped for shipment"
    subject.subject regex_match "delivery.*attempt.*failed"
    subject.subject regex_match "detected suspicious actvity"
    subject.subject regex_match "detected suspicious"
    subject.subject regex_match "docu sign"
    subject.subject regex_match "document for you"
    subject.subject regex_match "document has been sent to you via docusign"
    subject.subject regex_match "document is ready for signature"
    subject.subject regex_match "document.(?:submitted|received)"
    subject.subject regex_match "documented.*shared.*with.*you"
    subject.subject regex_match "docusign"
    subject.subject regex_match "dropbox.*document"
    subject.subject regex_match "e-?ma[il1]+ .{010}suspen"
    subject.subject regex_match "e-?ma[il1]{1} user"
    subject.subject regex_match "e-?ma[il1]{2} acc"
    subject.subject regex_match "e-?ma[il1]{2}.*up.?grade"
    subject.subject regex_match "e.?ma[il1]{2}.*server"
    subject.subject regex_match "e.?ma[il1]{2}.*suspend"
    subject.subject regex_match "email.update"
    subject.subject regex_match "encrypted message"
    subject.subject regex_match "failed delivery"
    subject.subject regex_match "faxed you"
    subject.subject regex_match "fedex tracking"
    subject.subject regex_match "file was shared"
    subject.subject regex_match "fraud(ulent)?.*charge"
    subject.subject regex_match "freefax"
    subject.subject regex_match "from.helpdesk"
    subject.subject regex_match "fu[il1]{2}.*ma[il1]+[ -]?box"
    subject.subject regex_match "fwd: due invoice paid"
    subject.subject regex_match "has shared"
    subject.subject regex_match "has.been.*suspended"
    subject.subject regex_match "has.been.limited"
    subject.subject regex_match "have.locked"
    subject.subject regex_match "he[li]p ?desk upgrade"
    subject.subject regex_match "heipdesk"
    subject.subject regex_match "i[il]iega[il]"
    subject.subject regex_match "ii[il]ega[il]"
    subject.subject regex_match "inbox is full"
    subject.subject regex_match "incoming e?mail"
    subject.subject regex_match "incoming.*fax"
    subject.subject regex_match "invitation to comment"
    subject.subject regex_match "invitation to edit"
    subject.subject regex_match "invoice due"
    subject.subject regex_match "left you a message"
    subject.subject regex_match "lock.*security"
    subject.subject regex_match "ma[il1]{1}[ -]?box.*quo"
    subject.subject regex_match "ma[il1]{2}[ -]?box.*fu[il1]"
    subject.subject regex_match "ma[il1]{2}box stor"
    subject.subject regex_match "ma[il1]{2}box.*[il1]{2}mit"
    subject.subject regex_match "mail on.?hold"
    subject.subject regex_match "mail.*box.*migration"
    subject.subject regex_match "mail.*de-?activat"
    subject.subject regex_match "mail.update.required"
    subject.subject regex_match "mails.*pending"
    subject.subject regex_match "message from"
    subject.subject regex_match "messages.*pending"
    subject.subject regex_match "missed.*shipping.*notification"
    subject.subject regex_match "missed.shipment.notification"
    subject.subject regex_match "must.update.your.account"
    subject.subject regex_match "new [sl][io]g?[nig][ -]?in from"
    subject.subject regex_match "new message"
    subject.subject regex_match "new sign in"
    subject.subject regex_match "new sign-in"
    subject.subject regex_match "new voice ?-?mail"
    subject.subject regex_match "new voicemail"
    subject.subject regex_match "notifications.*pending"
    subject.subject regex_match "office.*3.*6.*5.*suspend"
    subject.subject regex_match "office365"
    subject.subject regex_match "on desk"
    subject.subject regex_match "on google docs with you"
    subject.subject regex_match "online doc"
    subject.subject regex_match "out of space"
    subject.subject regex_match "password reset"
    subject.subject regex_match "password.*compromised"
    subject.subject regex_match "payment status"
    subject.subject regex_match "periodic maintenance"
    subject.subject regex_match "potential(ly)? unauthorized"
    subject.subject regex_match "quick reply"
    subject.subject regex_match "re: w-2"
    subject.subject regex_match "refund not approved"
    subject.subject regex_match "required"
    subject.subject regex_match "required: completed docusign"
    subject.subject regex_match "revised.*policy"
    subject.subject regex_match "ringcentral"
    subject.subject regex_match "scam"
    subject.subject regex_match "scanned image"
    subject.subject regex_match "scanned.?invoice"
    subject.subject regex_match "secured files"
    subject.subject regex_match "secured pdf"
    subject.subject regex_match "secured?.update"
    subject.subject regex_match "security alert"
    subject.subject regex_match "security breach"
    subject.subject regex_match "securlty"
    subject.subject regex_match "sign in attempt"
    subject.subject regex_match "sign-in attempt"
    subject.subject regex_match "signed.*delivery"
    subject.subject regex_match "staff review"
    subject.subject regex_match "status of your .{314}? ?delivery"
    subject.subject regex_match "susp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty"
    subject.subject regex_match "suspicious activity"
    subject.subject regex_match "suspicious.*sign.*[io]n"
    subject.subject regex_match "suspicious.activit"
    subject.subject regex_match "temporar(il)?y deactivate"
    subject.subject regex_match "temporar[il1]{2}y disab[li]ed"
    subject.subject regex_match "temporarily.*lock"
    subject.subject regex_match "termination.*notice"
    subject.subject regex_match "un-?usua[li].activity"
    subject.subject regex_match "unable.*deliver"
    subject.subject regex_match "unauthorized.*activit"
    subject.subject regex_match "unauthorized.device"
    subject.subject regex_match "unauthorized.sign.?in"
    subject.subject regex_match "undelivered message"
    subject.subject regex_match "unread.*doc"
    subject.subject regex_match "unrecognized login attempt"
    subject.subject regex_match "unrecognized.*activit"
    subject.subject regex_match "unrecognized.sign.?in"
    subject.subject regex_match "unusual.activity"
    subject.subject regex_match "upgrade immediately"
    subject.subject regex_match "upgrade.*account"
    subject.subject regex_match "upgrade.notice"
    subject.subject regex_match "urgent message"
    subject.subject regex_match "urgent"
    subject.subject regex_match "urgent.verification"
    subject.subject regex_match "v[il1]o[li1]at[il1]on security"
    subject.subject regex_match "va[il1]{1}date.*ma[il1]{2}[ -]?box"
    subject.subject regex_match "verification ?-?require"
    subject.subject regex_match "verification( )?-?need"
    subject.subject regex_match "verify.your?.account"
    subject.subject regex_match "wants to share"
    subject.subject regex_match "web ?-?ma[il1]{2}"
    subject.subject regex_match "web[ -]?ma[il1]{2}"
    subject.subject regex_match "will.be.suspended"
    subject.subject regex_match "you have notifications pending"
    subject.subject regex_match "your (customer )?account .as"
    subject.subject regex_match "your account"
    subject.subject regex_match "your amazon order"
    subject.subject regex_match "your document settlement"
    subject.subject regex_match "your order with amazon"
    subject.subject regex_match "your password has been compromised"
    subject.subject regex_match "your.office.365"
    subject.subject regex_match "your.online.access"
  not
    subject.subject starts_with "re:"
  not
     macro "all(body.links)"
  body.current_thread.text length_compare "2000"
  filter(body.links, not strings.ilike(.display_text, '*privacy*', '*terms of service*', 'Learn why this is important') or .display_text is null) length_compare "0"
  filter(body.links, not strings.ilike(.display_text, '*privacy*', '*terms of service*', 'Learn why this is important') or .display_text is null) length_compare "5"
  headers.in_reply_to is_null
  subject.subject length_compare "100"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
body.linksarray_any(no value, null check)excludes:body.links
body.current_thread.textregex_match[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}excludes:body.current_thread.text field:"body.current_thread.text" value:"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
subject.subjectstarts_withre:excludes:subject.subject field:"subject.subject" value:"re:"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
headers.in_reply_tois_null
  • (no value, null check)
field:"headers.in_reply_to" kind:is_null
subject.subjectregex_match
  • 38417
  • :completed
  • [il1]{2}mit.*ma[il1]{2} ?bo?x
  • [il][il][il]egai[ -]
  • [li][li][li]ega[li] attempt
  • [ng]-?[io]n .*block
  • [ng]-?[io]n .*cancel
  • [ng]-?[io]n .*deactiv
  • [ng]-?[io]n .*disabl
  • \bw2\b
  • \d{1,2}.\d{1,8}\s(BTC|ETH|SOL|(?:USD[CT])|XRP) Offer Waiting for(\sYour)?\sReview
  • ^final reminder: .*(?:overdue|resolve|access ends)
  • abandon.*package
  • about.your.account
  • acc(ou)?n?t (is )?on ho[li]d
  • acc(ou)?n?t.*terminat
  • acc(oun)?t.*[il1]{2}mitation
  • access.*limitation
  • account (will be )?block
  • account has been limited
  • account v[il]o[li]at
  • account.*de-?activat
  • account.*locked
  • account.*re-verification
  • account.*security
  • account.*suspension
  • account.has.been
  • account.has.expired
  • account.will.be.blocked
  • action required
  • action.*required
  • activity.*acc(oun)?t
  • almost full
  • almost.full
  • apd notifi cation
  • app[li]e.[il]d
  • are you at your desk
  • are you available
  • attached file to docusign
  • authenticate.*account
  • +153 more values (see full rule source)
field:"subject.subject" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential phishing: Tax form impersonation with payment request

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects messages impersonating tax-related communications that contain payment requests and PDF links, excluding legitimate tax service providers. The rule identifies tax terminology combined with payment solicitation language and PDF link references, which is a common pattern in tax season scams.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesBEC/Fraud, Credential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering, PDF

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and any([body.current_thread.text, subject.subject],
        regex.icontains(.,
                        'schedule.c\b',
                        'tax.form',
                        '1099\b',
                        '\bw-?2\b',
                        'tax.return',
                        'tax.preparation'
        )
        and (
          regex.icontains(body.current_thread.text,
                          "reply.with.your.payment",
                          "payment.details",
                          "send.payment.information",
                          "provide.payment",
                          "payment.method",
                          "billing.information",
                          "processing.fee",
                          "completion.fee"
          )
        )
        and any(body.links, strings.icontains(.display_text, "PDF"))
)
and not any(ml.nlu_classifier(body.current_thread.text).topics,
            .name in ("Events and Webinars", "Newsletters and Digests")
)
and not sender.email.domain.root_domain in (
  "intuit.com",
  "hrblock.com",
  "turbotax.com",
  "taxact.com",
  "freetaxusa.com",
  "geico.com",
  "eventshq.com",
  "square.com"
)
// 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 messages impersonating tax-related communications that contain payment requests and PDF links, excluding legitimate tax service providers. The rule identifies tax terminology combined with payment solicitation language and PDF link references, which is a common pattern in tax season scams.

  1. inbound message
  2. any of [body.current_thread.text, subject.subject] where all hold:
    • . matches any of 6 patterns
      • schedule.c\b
      • tax.form
      • 1099\b
      • \bw-?2\b
      • tax.return
      • tax.preparation
    • body.current_thread.text matches any of 8 patterns
      • reply.with.your.payment
      • payment.details
      • send.payment.information
      • provide.payment
      • payment.method
      • billing.information
      • processing.fee
      • completion.fee
    • any of body.links where:
      • .display_text contains 'PDF'
  3. not:
    • any of ml.nlu_classifier(body.current_thread.text).topics where:
      • .name in ('Events and Webinars', 'Newsletters and Digests')
  4. not:
    • sender.email.domain.root_domain in ('intuit.com', 'hrblock.com', 'turbotax.com', 'taxact.com', 'freetaxusa.com', 'geico.com', 'eventshq.com', 'square.com')
  5. 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, body.links, body.links[].display_text, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.icontains. Reference lists: $high_trust_sender_root_domains.

Indicators matched (15)

FieldMatchValue
regex.icontainsregexschedule.c\b
regex.icontainsregextax.form
regex.icontainsregex1099\b
regex.icontainsregex\bw-?2\b
regex.icontainsregextax.return
regex.icontainsregextax.preparation
regex.icontainsregexreply.with.your.payment
regex.icontainsregexpayment.details
regex.icontainsregexsend.payment.information
regex.icontainsregexprovide.payment
regex.icontainsregexpayment.method
regex.icontainsregexbilling.information
3 more
regex.icontainsregexprocessing.fee
regex.icontainsregexcompletion.fee
strings.icontainssubstringPDF

Stages and Predicates

Stage 1: mql_rule

and
  any([body.current_thread.text, subject.subject])
    and
      or
        [body.current_thread.text, subject.subject] regex_match "1099\\b"
        [body.current_thread.text, subject.subject] regex_match "\\bw-?2\\b"
        [body.current_thread.text, subject.subject] regex_match "schedule.c\\b"
        [body.current_thread.text, subject.subject] regex_match "tax.form"
        [body.current_thread.text, subject.subject] regex_match "tax.preparation"
        [body.current_thread.text, subject.subject] regex_match "tax.return"
      or
        body.current_thread.text regex_match "billing.information"
        body.current_thread.text regex_match "completion.fee"
        body.current_thread.text regex_match "payment.details"
        body.current_thread.text regex_match "payment.method"
        body.current_thread.text regex_match "processing.fee"
        body.current_thread.text regex_match "provide.payment"
        body.current_thread.text regex_match "reply.with.your.payment"
        body.current_thread.text regex_match "send.payment.information"
      any(body.links)
        body.links.display_text contains "PDF"
  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"
  not
    any(ml.nlu_classifier(body.current_thread.text).topics)
      ml.nlu_classifier(body.current_thread.text).topics.name in ["Events and Webinars", "Newsletters and Digests"]
  not
    sender.email.domain.root_domain in ["eventshq.com", "freetaxusa.com", "geico.com", "hrblock.com", "intuit.com", "square.com", "taxact.com", "turbotax.com"]
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ml.nlu_classifier(body.current_thread.text).topicsarray_any(no value, null check)excludes:ml.nlu_classifier(body.current_thread.text).topics
sender.email.domain.root_domainineventshq.com, freetaxusa.com, geico.com, hrblock.com, intuit.com, square.com, taxact.com, turbotax.comexcludes:sender.email.domain.root_domain

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Credential theft: JavaScript date manipulation in HTML body

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects inbound messages containing JavaScript that uses date manipulation functions (setDate/getDate) within script tags, combined with credential theft intent identified by NLU classification. This pattern is commonly used to evade detection by dynamically altering content or expiry logic while targeting user credentials.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, Scripting, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • type

Rule body

type.inbound
and regex.icontains(body.html.raw,
                    '<script[^>]*>[^<]*setDate\s*\(\s*[^<]*getDate\s*\(',
                    '<script[^>]*>[^<]*new\s+Date\s*\([^<]*(?:toLocaleDateString|toDateString|toISOString|toLocaleString)'
)
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name == "cred_theft"
)

Detection logic

Scope: inbound message.

Detects inbound messages containing JavaScript that uses date manipulation functions (setDate/getDate) within script tags, combined with credential theft intent identified by NLU classification. This pattern is commonly used to evade detection by dynamically altering content or expiry logic while targeting user credentials.

  1. inbound message
  2. body.html.raw matches any of 2 patterns
    • <script[^>]*>[^<]*setDate\s*\(\s*[^<]*getDate\s*\(
    • <script[^>]*>[^<]*new\s+Date\s*\([^<]*(?:toLocaleDateString|toDateString|toISOString|toLocaleString)
  3. any of ml.nlu_classifier(body.current_thread.text).intents where:
    • .name is 'cred_theft'

Inspects: body.current_thread.text, body.html.raw, type.inbound. Sensors: ml.nlu_classifier, regex.icontains.

Indicators matched (3)

FieldMatchValue
regex.icontainsregex<script[^>]*>[^<]*setDate\s*\(\s*[^<]*getDate\s*\(
regex.icontainsregex<script[^>]*>[^<]*new\s+Date\s*\([^<]*(?:toLocaleDateString|toDateString|toISOString|toLocaleString)
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft

Stages and Predicates

Stage 1: mql_rule

and
  or
    body.html.raw regex_match "<script[^>]*>[^<]*new\\s+Date\\s*\\([^<]*(?:toLocaleDateString|toDateString|toISOString|toLocaleString)"
    body.html.raw regex_match "<script[^>]*>[^<]*setDate\\s*\\(\\s*[^<]*getDate\\s*\\("
  any(ml.nlu_classifier(body.current_thread.text).intents)
    ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.html.rawregex_match
  • <script[^>]*>[^<]*new\s+Date\s*([^<]*(?:toLocaleDateString|toDateString|toISOString|toLocaleString)
  • <script[^>]*>[^<]*setDate\s*(\s*[^<]*getDate\s*(
field:"body.html.raw" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Fake email quarantine notification

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects phishing messages implying that emails have been delayed or blocked, prompting users to view, release, or delete pending messages.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • headers.domains
  • recipients
  • recipients.to
  • sender.email
  • type

Rule body

type.inbound
and length(body.links) < 10
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name == "cred_theft" and .confidence == "high"
  )
  or (
    length(body.current_thread.text) < 250
    and any(recipients.to,
            strings.icontains(body.current_thread.text, .email.domain.sld)
            or strings.icontains(body.current_thread.text, .email.local_part)
    )
  )
)
and not (
  length(ml.nlu_classifier(body.current_thread.text).topics) == 1
  and any(ml.nlu_classifier(body.current_thread.text).topics,
          .name == "Financial Communications" and .confidence != "low"
  )
)
and 3 of (
  strings.ilike(body.current_thread.text, "*review*"),
  strings.ilike(body.current_thread.text, "*incoming*"),
  strings.ilike(body.current_thread.text, "*release*"),
  strings.ilike(body.current_thread.text, "*quarantine*"),
  strings.ilike(body.current_thread.text, "*messages*"),
  strings.ilike(body.current_thread.text, "*server error*"),
  strings.ilike(body.current_thread.text, "*blocked*"),
  strings.ilike(body.current_thread.text, "*prevented*"),
  strings.ilike(body.current_thread.text, "*validation*"),
  strings.ilike(body.current_thread.text, "*notification*"),
  strings.ilike(body.current_thread.text, "*kindly*"),
  strings.ilike(body.current_thread.text, "*on hold*"),
  strings.ilike(body.current_thread.text, "*held*"),
  strings.ilike(body.current_thread.text, "*pending*"),
  strings.ilike(body.current_thread.text, "*stuck*"),
  strings.like(body.current_thread.text, "* MX *")
)
and (
  any(body.links,
      regex.icontains(.display_text,
                      "view",
                      "release",
                      "message",
                      "delete",
                      "recover",
                      "SSO",
                      "sign in"
      )
  )
  or (
    length(body.links) < 3
    and any(body.links,
            any(recipients.to,
                .email.domain.root_domain == ..display_url.domain.root_domain
                and ..mismatched
            )
    )
  )
)
and not any(body.links,
            regex.icontains(.display_text,
                            "view document",
                            "review (&|and) sign document"
            )
)
and sender.email.domain.root_domain not in (
  "bing.com",
  "microsoft.com",
  "microsoftonline.com",
  "microsoftsupport.com",
  "microsoft365.com",
  "office.com",
  "office365.com",
  "onedrive.com",
  "sharepointonline.com",
  "yammer.com",
  "ppops.net"
)

// negate org domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $org_domains
    and (
      not headers.auth_summary.dmarc.pass
      // MS quarantine digest emails from an org domain are router "internally" to MS, therefore, there is no authentication information
      or not (
        headers.auth_summary.dmarc.pass is null
        and all(headers.domains,
                .root_domain in (
                  "outlook.com",
                  "office365.com",
                  "exchangelabs.com"
                )
        )
        // typical emails from freemail Outlook accounts are from prod.outlook.com
        and strings.ends_with(headers.message_id, "protection.outlook.com>")
      )
    )
  )
  or sender.email.domain.root_domain not in $org_domains
)

// 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 not profile.by_sender().solicited
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

Detects phishing messages implying that emails have been delayed or blocked, prompting users to view, release, or delete pending messages.

  1. inbound message
  2. length(body.links) < 10
  3. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'cred_theft'
      • .confidence is 'high'
    • all of:
      • length(body.current_thread.text) < 250
      • any of recipients.to where any holds:
        • strings.icontains(body.current_thread.text)
        • strings.icontains(body.current_thread.text)
  4. not:
    • all of:
      • length(ml.nlu_classifier(body.current_thread.text).topics) is 1
      • any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
        • .name is 'Financial Communications'
        • .confidence is not 'low'
  5. at least 3 of 16: body.current_thread.text matches any of 16 patterns
    • *review*
    • *incoming*
    • *release*
    • *quarantine*
    • *messages*
    • *server error*
    • *blocked*
    • *prevented*
    • *validation*
    • *notification*
    • *kindly*
    • *on hold*
    • *held*
    • *pending*
    • *stuck*
    • * MX *
  6. any of:
    • any of body.links where:
      • .display_text matches any of 7 patterns
        • view
        • release
        • message
        • delete
        • recover
        • SSO
        • sign in
    • all of:
      • length(body.links) < 3
      • any of body.links where:
        • any of recipients.to where all hold:
          • .email.domain.root_domain is .display_url.domain.root_domain
          • .mismatched
  7. not:
    • any of body.links where:
      • .display_text matches any of 2 patterns
        • view document
        • review (&|and) sign document
  8. sender.email.domain.root_domain not in ('bing.com', 'microsoft.com', 'microsoftonline.com', 'microsoftsupport.com', 'microsoft365.com', 'office.com', 'office365.com', 'onedrive.com', 'sharepointonline.com', 'yammer.com', 'ppops.net')
  9. any of:
    • all of:
      • sender.email.domain.root_domain in $org_domains
      • any of:
        • not:
          • headers.auth_summary.dmarc.pass
        • not:
          • all of:
            • headers.auth_summary.dmarc.pass is missing
            • all of headers.domains where:
              • .root_domain in ('outlook.com', 'office365.com', 'exchangelabs.com')
            • headers.message_id ends with 'protection.outlook.com>'
    • sender.email.domain.root_domain not in $org_domains
  10. 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
  11. not:
    • profile.by_sender().solicited
  12. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].display_url.domain.root_domain, body.links[].mismatched, headers.auth_summary.dmarc.pass, headers.domains, headers.domains[].root_domain, headers.message_id, recipients.to, recipients.to[].email.domain.root_domain, recipients.to[].email.domain.sld, recipients.to[].email.local_part, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, strings.ends_with, strings.icontains, strings.ilike, strings.like. Reference lists: $high_trust_sender_root_domains, $org_domains.

Indicators matched (25)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh
strings.ilikesubstring*review*
strings.ilikesubstring*incoming*
strings.ilikesubstring*release*
strings.ilikesubstring*quarantine*
strings.ilikesubstring*messages*
strings.ilikesubstring*server error*
strings.ilikesubstring*blocked*
strings.ilikesubstring*prevented*
strings.ilikesubstring*validation*
strings.ilikesubstring*notification*
13 more
strings.ilikesubstring*kindly*
strings.ilikesubstring*on hold*
strings.ilikesubstring*held*
strings.ilikesubstring*pending*
strings.ilikesubstring*stuck*
strings.likesubstring* MX *
regex.icontainsregexview
regex.icontainsregexrelease
regex.icontainsregexmessage
regex.icontainsregexdelete
regex.icontainsregexrecover
regex.icontainsregexSSO
regex.icontainsregexsign in

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(body.links)
        any(recipients.to)
          and
            body.links.mismatched eq "true"
            recipients.to.email.domain.root_domain cross_field_compare "body.links.display_url.domain.root_domain"
      body.links length_compare "3"
    any(body.links)
      or
        body.links.display_text regex_match "SSO"
        body.links.display_text regex_match "delete"
        body.links.display_text regex_match "message"
        body.links.display_text regex_match "recover"
        body.links.display_text regex_match "release"
        body.links.display_text regex_match "sign in"
        body.links.display_text regex_match "view"
  or
    and
      or
        not
          and
            headers.auth_summary.dmarc.pass is_null
            headers.message_id ends_with "protection.outlook.com>"
             macro "all(headers.domains)"
        not
          headers.auth_summary.dmarc.pass eq "true"
       macro "sender.email.domain.root_domain in org_domains"
     macro "sender.email.domain.root_domain not in org_domains"
  not
    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 "Financial Communications"
      ml.nlu_classifier(body.current_thread.text).topics length_compare "1"
  not
    any(body.links)
      or
        body.links.display_text regex_match "review (&|and) sign document"
        body.links.display_text regex_match "view document"
  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).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "cred_theft"
    and
      any(recipients.to)
        strings.icontains func_call "strings.icontains(body.current_thread.text)"
      body.current_thread.text length_compare "250"
  or
    body.current_thread.text match " MX "
    body.current_thread.text match "blocked"
    body.current_thread.text match "held"
    body.current_thread.text match "incoming"
    body.current_thread.text match "kindly"
    body.current_thread.text match "messages"
    body.current_thread.text match "notification"
    body.current_thread.text match "on hold"
    body.current_thread.text match "pending"
    body.current_thread.text match "prevented"
    body.current_thread.text match "quarantine"
    body.current_thread.text match "release"
    body.current_thread.text match "review"
    body.current_thread.text match "server error"
    body.current_thread.text match "stuck"
    body.current_thread.text match "validation"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  not
    profile.by_sender func_call "profile.by_sender().solicited"
  not
    sender.email.domain.root_domain in ["bing.com", "microsoft.com", "microsoft365.com", "microsoftonline.com", "microsoftsupport.com", "office.com", "office365.com", "onedrive.com", "ppops.net", "sharepointonline.com", "yammer.com"]
  body.links length_compare "10"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ml.nlu_classifier(body.current_thread.text).topicsarray_any(no value, null check)excludes:ml.nlu_classifier(body.current_thread.text).topics
ml.nlu_classifier(body.current_thread.text).topicslength_compare1excludes:ml.nlu_classifier(body.current_thread.text).topics field:"ml.nlu_classifier(body.current_thread.text).topics" value:"1"
body.linksarray_any(no value, null check)excludes:body.links
sender.email.domain.root_domaininbing.com, microsoft.com, microsoft365.com, microsoftonline.com, microsoftsupport.com, office.com, office365.com, onedrive.com, ppops.net, sharepointonline.com, yammer.comexcludes:sender.email.domain.root_domain

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • * MX *
  • *blocked*
  • *held*
  • *incoming*
  • *kindly*
  • *messages*
  • *notification*
  • *on hold*
  • *pending*
  • *prevented*
  • *quarantine*
  • *release*
  • *review*
  • *server error*
  • *stuck*
  • *validation*
field:"body.current_thread.text" kind:wildcard
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Fake Zoho Sign template abuse

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

This rule captures credential phishing attempts abusing the Zoho Sign template. The rule looks for artifacts of the Hijacked Zoho link and other template constructs.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, Open redirect, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • body.links
  • recipients
  • recipients.to
  • type

Rule body

type.inbound
and 0 < length(body.links) < 10
// Link contains Start Signing
and any(body.links, .display_text == "Start Signing")

// Zoho artifact in html body
and regex.contains(body.html.raw,
                   'title="Original URL: https:\/\/sign\.zoho\.com\/zsguest\?[^"]*action_type=SIGN\.[^"]*Click or tap if you trust this link\."'
)
// but the Zoho link is not active
and not any(body.links, .href_url.domain.root_domain == "zoho.com")

// and the body thread contains the Sender + recipient domain
and any(recipients.to,
        strings.icontains(body.current_thread.text,
                          strings.concat("Sender\n", .email.domain.domain)
        )
)

Detection logic

Scope: inbound message.

This rule captures credential phishing attempts abusing the Zoho Sign template. The rule looks for artifacts of the Hijacked Zoho link and other template constructs.

  1. inbound message
  2. all of:
    • length(body.links) > 0
    • length(body.links) < 10
  3. any of body.links where:
    • .display_text is 'Start Signing'
  4. body.html.raw matches 'title="Original URL: https:\\/\\/sign\\.zoho\\.com\\/zsguest\\?[^"]*action_type=SIGN\\.[^"]*Click or tap if you trust this link\\."'
  5. not:
    • any of body.links where:
      • .href_url.domain.root_domain is 'zoho.com'
  6. any of recipients.to where:
    • strings.icontains(body.current_thread.text)

Inspects: body.current_thread.text, body.html.raw, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, recipients.to, recipients.to[].email.domain.domain, type.inbound. Sensors: regex.contains, strings.concat, strings.icontains.

Indicators matched (2)

FieldMatchValue
body.links[].display_textequalsStart Signing
regex.containsregextitle="Original URL: https:\/\/sign\.zoho\.com\/zsguest\?[^"]*action_type=SIGN\.[^"]*Click or tap if you trust this link\."

Stages and Predicates

Stage 1: mql_rule

and
  not
    any(body.links)
      body.links.href_url.domain.root_domain eq "zoho.com"
  any(body.links)
    body.links.display_text eq "Start Signing"
  any(recipients.to)
    strings.icontains func_call "strings.icontains(body.current_thread.text)"
  body.html.raw regex_match "title=\"Original URL: https:\\/\\/sign\\.zoho\\.com\\/zsguest\\?[^\"]*action_type=SIGN\\.[^\"]*Click or tap if you trust this link\\.\""
  body.links length_compare "0"
  body.links length_compare "10"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
body.linksarray_any(no value, null check)excludes:body.links

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.html.rawregex_match
  • title="Original URL: https:\/\/sign.zoho.com\/zsguest?[^"]*action_type=SIGN.[^"]*Click or tap if you trust this link."
field:"body.html.raw" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Impersonation: Internal corporate services

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects phishing attempts that impersonate corporate services such as HR, helpdesk, and benefits, using specific language in the subject or sender's name and containing suspicious links from low-reputation or mass-mailing domains.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Employee, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.links
  • headers
  • headers.auth_summary
  • headers.domains
  • headers.hops
  • sender.email
  • subject
  • type

Rule body

type.inbound
// use distinct "urls" (without query params) to determine number of links
and 0 < length(distinct(body.links,
                        // strip out query params to determine
                        // the unique number of links
                        strings.concat(.href_url.scheme,
                                       .href_url.domain.domain,
                                       .href_url.path
                        )
               )
) <= 8

// HR language found in subject
and (
  (
    length(subject.subject) > 20
    and regex.icontains(subject.subject,
                        '(time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N',
                        // shorten the distance to 3 or less words for the word "review"
                        // special handling of benefits
                        '\breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)',
                        // handle the year in the subject, and expand the distance to 5 or less words
                        '20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)'
    )
  )

  // or HR language found in sender
  or (
    regex.icontains(sender.display_name,
                    '(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support'
    )
    and not regex.icontains(sender.display_name,
                            "forum|employee voice|briefs|newsletter|screening"
    )
    and not regex.icontains(sender.display_name,
                            "HR (new|vue|view|tech admin|global)"
    )
    and not strings.icontains(sender.display_name, "get it")
  )

  // or assessment report language found in body
  or (
    regex.icontains(body.current_thread.text,
                    '20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report'
    )
  )

  // or HR department language found in body via NLU
  or any(ml.nlu_classifier(body.current_thread.text).entities,
         .name in ("org", "sender")
         and regex.icontains(.text,
                             '\bhr\b',
                             'human resources',
                             'operations department'
         )
  )
)

// suspicious display_text
and (
  any(body.links,
      regex.icontains(.display_text,
                      '(?:access|account|allow|click|deny|download|goto|keep|new|open|release|verify|view|Vιew).{0,10}(?:access|attachment|change|current|doc|document|download|fax|file|handbook|here|message|polic(?:y|ie)|report|request|same)s?'
      )
      and not strings.ilike(.display_text, "*unsub*")
      and not strings.ilike(.display_text, "*privacy?policy*")
      and not strings.ilike(.href_url.url, "*privacy?policy*")
      and not strings.ilike(.display_text, "*REGISTER*")

      // from a low reputation link
      and (
        not .href_url.domain.root_domain in $org_domains
        and (
          (
            .href_url.domain.root_domain not in $tranco_1m
            or .href_url.domain.domain in $free_file_hosts
            or .href_url.domain.root_domain in $free_file_hosts
            or .href_url.domain.root_domain in $free_subdomain_hosts
            or .href_url.domain.domain in $url_shorteners
            or .href_url.domain.domain in $social_landing_hosts
          )
          or
          // or mass mailer link, masks the actual URL
          .href_url.domain.root_domain in (
            "hubspotlinks.com",
            "mandrillapp.com",
            "sendgrid.net",
            "rs6.net",
            "mailanyone.net",
            "perspectivefunnel.co"
          )
        )
      )
  )
  // or credential theft confidence high
  or (
    length(body.links) > 0
    and any(ml.nlu_classifier(body.current_thread.text).intents,
            .name == "cred_theft" and .confidence == "high"
    )
    and not sender.email.domain.root_domain in (
      "servicenowservices.com",
      "workplaceextras.com",
      "tempo.io",
      "or.us",
      "proofpoint.com"
    )
  )
  or any(filter(attachments,
                .content_type == "message/rfc822" or .file_extension in ('eml')
         ),
         any(file.parse_eml(.).attachments,
             any(file.explode(.),
                 regex.icontains(.scan.ocr.raw, 'scan|camera')
                 and regex.icontains(.scan.ocr.raw, '\bQR\b|Q\.R\.|barcode')
             )
         )
  )
)
// negate messages where "click here" was found and was a link actually an unsub link
// this method allows for matching on other 'click here' links if they are present
and not (
  length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0
  and (
    length(filter(body.links, strings.icontains(.display_text, 'click here'))) == strings.icount(body.current_thread.text,
                                                                                                 'click here to unsubscribe'
    )
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    (
      sender.email.domain.root_domain in $high_trust_sender_root_domains
      or sender.email.domain.root_domain in $org_domains
    )
    and not headers.auth_summary.dmarc.pass
  )
  or (
    sender.email.domain.root_domain not in $high_trust_sender_root_domains
    and sender.email.domain.root_domain not in $org_domains
  )
)
// not from sharepointonline actual
and not (
  sender.email.domain.root_domain == "sharepointonline.com"
  and strings.ends_with(headers.message_id, '@odspnotify>')
  and strings.starts_with(headers.message_id, "<Spo")
)
// netate common FP topics
and not any(beta.ml_topic(body.current_thread.text).topics,
            .name in (
              "Events and Webinars",
              "Advertising and Promotions",
              "Newsletters and Digests"
            )
            and .confidence == "high"
)
// negate common helpdesk/HR platforms
and not any(headers.domains,
            .root_domain in (
              "freshemail.io",
              "zendesk.com",
              "employeenavigator.com",
              "saashr.com" // Kronos owned Saas HR offering
            )
)
// negate observed HR newsletters
and not (
  any(headers.hops,
      strings.icontains(.authentication_results.spf_details.designator,
                        "constantcontact.com"
      )
  )
  and strings.starts_with(sender.email.local_part, 'newsletters-hr')
  and sender.email.domain.root_domain == "ccsend.com"
)
// the message is unsolicited and no false positives
and (
  not profile.by_sender_email().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and profile.by_sender().any_messages_benign
    and not (headers.auth_summary.dmarc.pass and headers.auth_summary.spf.pass)
  )
)
// negate instances where proofpoint sends a review of a reported message via analyzer
and not (
  sender.email.email == "analyzer@analyzer.securityeducation.com"
  and any(headers.domains, .root_domain == "pphosted.com")
  and headers.auth_summary.spf.pass
  and headers.auth_summary.dmarc.pass
)

Detection logic

Scope: inbound message.

Detects phishing attempts that impersonate corporate services such as HR, helpdesk, and benefits, using specific language in the subject or sender's name and containing suspicious links from low-reputation or mass-mailing domains.

  1. inbound message
  2. all of:
    • length(distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path))) > 0
    • length(distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path))) ≤ 8
  3. any of:
    • all of:
      • length(subject.subject) > 20
      • subject.subject matches any of 3 patterns
        • (time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N
        • \breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
        • 20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
    • all of:
      • sender.display_name matches '(Employ|Time.{0,3}sheet|\\bHR\\b|Human R|Handbook|\\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support'
      • not:
        • sender.display_name matches 'forum|employee voice|briefs|newsletter|screening'
      • not:
        • sender.display_name matches 'HR (new|vue|view|tech admin|global)'
      • not:
        • sender.display_name contains 'get it'
    • body.current_thread.text matches '20\\d{2}(?:[[:punct:]](?:20)?\\d{2})? (?:\\w+ )?assessment report'
    • any of ml.nlu_classifier(body.current_thread.text).entities where all hold:
      • .name in ('org', 'sender')
      • .text matches any of 3 patterns
        • \bhr\b
        • human resources
        • operations department
  4. any of:
    • any of body.links where all hold:
      • .display_text matches '(?:access|account|allow|click|deny|download|goto|keep|new|open|release|verify|view|Vιew).{0,10}(?:access|attachment|change|current|doc|document|download|fax|file|handbook|here|message|polic(?:y|ie)|report|request|same)s?'
      • not:
        • .display_text matches '*unsub*'
      • not:
        • .display_text matches '*privacy?policy*'
      • not:
        • .href_url.url matches '*privacy?policy*'
      • not:
        • .display_text matches '*REGISTER*'
      • all of:
        • not:
          • .href_url.domain.root_domain in $org_domains
        • any of:
          • any of:
            • .href_url.domain.root_domain not in $tranco_1m
            • .href_url.domain.domain in $free_file_hosts
            • .href_url.domain.root_domain in $free_file_hosts
            • .href_url.domain.root_domain in $free_subdomain_hosts
            • .href_url.domain.domain in $url_shorteners
            • .href_url.domain.domain in $social_landing_hosts
          • .href_url.domain.root_domain in ('hubspotlinks.com', 'mandrillapp.com', 'sendgrid.net', 'rs6.net', 'mailanyone.net', 'perspectivefunnel.co')
    • all of:
      • length(body.links) > 0
      • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
        • .name is 'cred_theft'
        • .confidence is 'high'
      • not:
        • sender.email.domain.root_domain in ('servicenowservices.com', 'workplaceextras.com', 'tempo.io', 'or.us', 'proofpoint.com')
    • any of filter(attachments) where:
      • any of file.parse_eml(.).attachments where:
        • any of file.explode(.) where all hold:
          • .scan.ocr.raw matches 'scan|camera'
          • .scan.ocr.raw matches '\\bQR\\b|Q\\.R\\.|barcode'
  5. not:
    • all of:
      • length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0
      • length(filter(body.links, strings.icontains(.display_text, 'click here'))) is strings.icount(body.current_thread.text, 'click here to unsubscribe')
  6. any of:
    • all of:
      • any of:
        • sender.email.domain.root_domain in $high_trust_sender_root_domains
        • sender.email.domain.root_domain in $org_domains
      • not:
        • headers.auth_summary.dmarc.pass
    • all of:
      • sender.email.domain.root_domain not in $high_trust_sender_root_domains
      • sender.email.domain.root_domain not in $org_domains
  7. not:
    • all of:
      • sender.email.domain.root_domain is 'sharepointonline.com'
      • headers.message_id ends with '@odspnotify>'
      • headers.message_id starts with '<Spo'
  8. not:
    • any of beta.ml_topic(body.current_thread.text).topics where all hold:
      • .name in ('Events and Webinars', 'Advertising and Promotions', 'Newsletters and Digests')
      • .confidence is 'high'
  9. not:
    • any of headers.domains where:
      • .root_domain in ('freshemail.io', 'zendesk.com', 'employeenavigator.com', 'saashr.com')
  10. not:
    • all of:
      • any of headers.hops where:
        • .authentication_results.spf_details.designator contains 'constantcontact.com'
      • sender.email.local_part starts with 'newsletters-hr'
      • sender.email.domain.root_domain is 'ccsend.com'
  11. any of:
    • not:
      • profile.by_sender_email().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • profile.by_sender().any_messages_benign
      • not:
        • all of:
          • headers.auth_summary.dmarc.pass
          • headers.auth_summary.spf.pass
  12. not:
    • all of:
      • sender.email.email is 'analyzer@analyzer.securityeducation.com'
      • any of headers.domains where:
        • .root_domain is 'pphosted.com'
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass

Inspects: attachments[].content_type, attachments[].file_extension, body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.links[].href_url.path, body.links[].href_url.scheme, body.links[].href_url.url, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.domains, headers.domains[].root_domain, headers.hops, headers.hops[].authentication_results.spf_details.designator, headers.message_id, sender.display_name, sender.email.domain.root_domain, sender.email.email, sender.email.local_part, subject.subject, type.inbound. Sensors: beta.ml_topic, file.explode, file.parse_eml, ml.nlu_classifier, profile.by_sender, profile.by_sender_email, regex.icontains, strings.concat, strings.ends_with, strings.icontains, strings.icount, strings.ilike, strings.starts_with. Reference lists: $free_file_hosts, $free_subdomain_hosts, $high_trust_sender_root_domains, $org_domains, $social_landing_hosts, $tranco_1m, $url_shorteners.

Indicators matched (23)

FieldMatchValue
regex.icontainsregex(time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N
regex.icontainsregex\breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
regex.icontainsregex20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
regex.icontainsregex(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support
regex.icontainsregex20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report
ml.nlu_classifier(body.current_thread.text).entities[].namememberorg
ml.nlu_classifier(body.current_thread.text).entities[].namemembersender
regex.icontainsregex\bhr\b
regex.icontainsregexhuman resources
regex.icontainsregexoperations department
regex.icontainsregex(?:access|account|allow|click|deny|download|goto|keep|new|open|release|verify|view|Vιew).{0,10}(?:access|attachment|change|current|doc|document|download|fax|file|handbook|here|message|polic(?:y|ie)|report|request|same)s?
body.links[].href_url.domain.root_domainmemberhubspotlinks.com
11 more
body.links[].href_url.domain.root_domainmembermandrillapp.com
body.links[].href_url.domain.root_domainmembersendgrid.net
body.links[].href_url.domain.root_domainmemberrs6.net
body.links[].href_url.domain.root_domainmembermailanyone.net
body.links[].href_url.domain.root_domainmemberperspectivefunnel.co
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh
attachments[].content_typeequalsmessage/rfc822
attachments[].file_extensionmembereml
regex.icontainsregexscan|camera
regex.icontainsregex\bQR\b|Q\.R\.|barcode

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(filter(attachments))
      any(file.parse_eml(filter(attachments)).attachments)
        any(file.explode(file.parse_eml(filter(attachments)).attachments))
          and
            file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.ocr.raw regex_match "\\bQR\\b|Q\\.R\\.|barcode"
            file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.ocr.raw regex_match "scan|camera"
    any(body.links)
      and
        not
          body.links.display_text match "REGISTER"
        not
          body.links.display_text match "privacy?policy"
        not
          body.links.display_text match "unsub"
        or
          body.links.href_url.domain.root_domain in ["hubspotlinks.com", "mailanyone.net", "mandrillapp.com", "perspectivefunnel.co", "rs6.net", "sendgrid.net"]
           macro "body.links[].href_url.domain.domain in free_file_hosts"
           macro "body.links[].href_url.domain.domain in social_landing_hosts"
           macro "body.links[].href_url.domain.domain in url_shorteners"
           macro "body.links[].href_url.domain.root_domain in free_file_hosts"
           macro "body.links[].href_url.domain.root_domain in free_subdomain_hosts"
           macro "body.links[].href_url.domain.root_domain not in tranco_1m"
        not
          body.links.href_url.url match "privacy?policy"
        not
           macro "body.links[].href_url.domain.root_domain in org_domains"
        body.links.display_text regex_match "(?:access|account|allow|click|deny|download|goto|keep|new|open|release|verify|view|Vιew).{0,10}(?:access|attachment|change|current|doc|document|download|fax|file|handbook|here|message|polic(?:y|ie)|report|request|same)s?"
    and
      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 "cred_theft"
      not
        sender.email.domain.root_domain in ["or.us", "proofpoint.com", "servicenowservices.com", "tempo.io", "workplaceextras.com"]
      body.links length_compare "0"
  or
    and
      not
        and
          headers.auth_summary.dmarc.pass eq "true"
          headers.auth_summary.spf.pass eq "true"
      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().any_messages_benign"
      profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
    not
      profile.by_sender_email func_call "profile.by_sender_email().solicited"
  or
    any(ml.nlu_classifier(body.current_thread.text).entities)
      and
        or
          ml.nlu_classifier(body.current_thread.text).entities.text regex_match "\\bhr\\b"
          ml.nlu_classifier(body.current_thread.text).entities.text regex_match "human resources"
          ml.nlu_classifier(body.current_thread.text).entities.text regex_match "operations department"
        ml.nlu_classifier(body.current_thread.text).entities.name in ["org", "sender"]
    and
      not
        sender.display_name contains "get it"
      not
        sender.display_name regex_match "HR (new|vue|view|tech admin|global)"
      not
        sender.display_name regex_match "forum|employee voice|briefs|newsletter|screening"
      sender.display_name regex_match "(Employ|Time.{0,3}sheet|\\bHR\\b|Human R|Handbook|\\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support"
    and
      or
        subject.subject regex_match "(time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\\b|compensation|salary|\\bpay(?:roll)?\\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N"
        subject.subject regex_match "20\\d{2}\\b(?:\\w+(?:\\s\\w+)?|[[:punct:]]+|\\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\\b|compensation|salary|bonus|\\bpay(?:roll)?\\b)"
        subject.subject regex_match "\\breview\\b(?:\\w+(?:\\s\\w+)?|[[:punct:]]+|\\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\\b|compensation|salary|bonus|\\bpay(?:roll)?\\b)"
      subject.subject length_compare "20"
    body.current_thread.text regex_match "20\\d{2}(?:[[:punct:]](?:20)?\\d{2})? (?:\\w+ )?assessment report"
  not
    any(beta.ml_topic(body.current_thread.text).topics)
      and
        beta.ml_topic(body.current_thread.text).topics.confidence eq "high"
        beta.ml_topic(body.current_thread.text).topics.name in ["Advertising and Promotions", "Events and Webinars", "Newsletters and Digests"]
  or
    and
      not
        headers.auth_summary.dmarc.pass eq "true"
      or
         macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
         macro "sender.email.domain.root_domain in org_domains"
    and
       macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
       macro "sender.email.domain.root_domain not in org_domains"
  not
    and
      any(headers.domains)
        headers.domains.root_domain eq "pphosted.com"
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.spf.pass eq "true"
      sender.email.email eq "analyzer@analyzer.securityeducation.com"
  not
    and
      any(headers.hops)
        headers.hops.authentication_results.spf_details.designator contains "constantcontact.com"
      sender.email.domain.root_domain eq "ccsend.com"
      sender.email.local_part starts_with "newsletters-hr"
  not
    and
      filter(body.links, strings.icontains(.display_text, 'click here')) length_compare "0"
      length func_call "length(filter(body.links, strings.icontains(.display_text, 'click here'))) == strings.icount(body.current_thread.text, 'click here to unsubscribe')"
  not
    any(headers.domains)
      headers.domains.root_domain in ["employeenavigator.com", "freshemail.io", "saashr.com", "zendesk.com"]
  not
    and
      headers.message_id ends_with "@odspnotify>"
      headers.message_id starts_with "<Spo"
      sender.email.domain.root_domain eq "sharepointonline.com"
  distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path)) length_compare "0"
  distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path)) length_compare "8"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
beta.ml_topic(body.current_thread.text).topicsarray_any(no value, null check)excludes:beta.ml_topic(body.current_thread.text).topics
headers.domainsarray_any(no value, null check)excludes:headers.domains
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.spf.passeqtrueexcludes:headers.auth_summary.spf.pass field:"headers.auth_summary.spf.pass" value:"true"
sender.email.emaileqanalyzer@analyzer.securityeducation.comexcludes:sender.email.email field:"sender.email.email" value:"analyzer@analyzer.securityeducation.com"
headers.hopsarray_any(no value, null check)excludes:headers.hops
sender.email.domain.root_domaineqccsend.comexcludes:sender.email.domain.root_domain field:"sender.email.domain.root_domain" value:"ccsend.com"
sender.email.local_partstarts_withnewsletters-hrexcludes:sender.email.local_part field:"sender.email.local_part" value:"newsletters-hr"
filter(body.links, strings.icontains(.display_text, 'click here'))length_compare0excludes:filter(body.links, strings.icontains(.display_text, 'click here')) field:"filter(body.links, strings.icontains(.display_text, 'click here'))" value:"0"
headers.message_idends_with@odspnotify>excludes:headers.message_id field:"headers.message_id" value:"@odspnotify>"
headers.message_idstarts_with<Spoexcludes:headers.message_id field:"headers.message_id" value:"<Spo"
sender.email.domain.root_domaineqsharepointonline.comexcludes:sender.email.domain.root_domain field:"sender.email.domain.root_domain" value:"sharepointonline.com"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • 20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report
field:"body.current_thread.text" kind:regex_match value:"20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report"
sender.display_nameregex_match
    • (Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)
    • Internal.?Comm
    • Enroll?ment Service
    • Open Enroll?ment
    • Admin Support
field:"sender.display_name" kind:regex_match
subject.subjectregex_match
    • (time.{0,4}sheet)
    • (employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)
    • (HR|Human Resources).{0,5}ADM[il]N
  • 20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
  • \breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
field:"subject.subject" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Service Abuse: Nifty.com with impersonation

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects emails from nifty.com where the sender's local part matches a recipient's local part or organizational SLD, which has been observed in credential harvesting campaigns

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSpoofing

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • recipients
  • recipients.to
  • sender.email
  • type

Rule body

type.inbound
and sender.email.domain.root_domain == "nifty.com"
and (
  sender.email.local_part in map(recipients.to, .email.local_part)
  or sender.email.local_part in $org_slds
)
and ml.nlu_classifier(body.current_thread.text).language != "japanese"

// and no false positives and not solicited
and not profile.by_sender_email().any_messages_benign

Detection logic

Scope: inbound message.

Detects emails from nifty.com where the sender's local part matches a recipient's local part or organizational SLD, which has been observed in credential harvesting campaigns

  1. inbound message
  2. sender.email.domain.root_domain is 'nifty.com'
  3. any of:
    • sender.email.local_part in map(recipients.to, .email.local_part)
    • sender.email.local_part in $org_slds
  4. ml.nlu_classifier(body.current_thread.text).language is not 'japanese'
  5. not:
    • profile.by_sender_email().any_messages_benign

Inspects: body.current_thread.text, recipients.to, recipients.to[].email.local_part, sender.email.domain.root_domain, sender.email.local_part, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender_email. Reference lists: $org_slds.

Indicators matched (1)

FieldMatchValue
sender.email.domain.root_domainequalsnifty.com

Stages and Predicates

Stage 1: mql_rule

and
  not
    profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
  or
     macro "sender.email.local_part in map(recipients.to, .email.local_part)"
     macro "sender.email.local_part in org_slds"
  ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language != japanese"
  sender.email.domain.root_domain eq "nifty.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

Suspected cross-site scripting (XSS) found in subject

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

This rule detects Cross-Site Scripting (XSS) attempts within email subjects. It bypasses messages from highly trusted domains unless they fail authentication. However, the rule remains flexible, triggering even for trusted domains when emails are sent from Google Groups, ensuring thorough protection against potential threats while minimizing false positives.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, Scripting

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • headers
  • headers.hops
  • sender.email
  • subject
  • type

Rule body

type.inbound
// subject contains suspected cross site scripting
and regex.icontains(subject.subject,
                    '(?:[<]|%(25)?3c|\\u003c|\\x3c|&[lg]t;|&n[vw][lg]t;)\/?(?:script(?:\s*/?\s*src\s*=)?|div|iframe|embed|object|style|form|meta|link|svg|img|audio|video|source|body|input|textarea|select|noscript|(?:/|%(25)?2f)?title|(?:/|%(25)?2f)?textarea|(?:/|%(25)?2f)?style|(?:/|%(25)?2f)?template|(?:/|%(25)?2f)?noembed)',
                    // constructor chain pattern
                    'constructor\.constructor|\[\s*constructor\s*\]|\.__proto__|\[constructor\]'
)

// and contains html or url encoded strings, hex escaped strings, opening or closing html tags, or escaped non word characters
// subject contains common event handlers
and regex.icontains(subject.subject,
                    '(?:\b|%[a-f0-9]{2})(?:on(?:abort|blur|change|click|dblclick|error|focus|load|mouse(?:over|out|move|down|up)|key(?:down|up|press)|reset|select|submit|unload)|srcdoc|src\s*(?:=|%(?:25)?3d))',
                    // subject contains javascript funcitons
                    '(?:\b|%(?:25)?[a-f0-9]{2})(?:javascript|eval|settimeout|setinterval|document\.(?:cookie|write|location|createElement|body|appendChild)|fetch|constructor|__proto__|prototype|atob|getScript|script(?:\s|%(?:25)?20)src)(?:\b|%(?:25)?[a-f0-9]{2})',
                    // url encoded forms of script src
                    '(?:\b|%(?:25)?[a-f0-9]{2})script(?:\s|%(?:25)?20)src(?:\b|%(?:25)?[a-f0-9]{2})'
)
and regex.icontains(subject.subject,
                    // Pattern 1: Quote followed by various special characters in encoded/literal forms:
                    // - < > angle brackets (%3C, %3E, literal, &lt;, &gt;)
                    // - quotes (&quot;, &apos;)
                    // - parentheses (&lpar;, &rpar;)
                    // - curly braces (&lcub;, &rcub;)
                    // - square brackets (&lsqb;, &rsqb;)
                    // - equals sign (&equals;)
                    // - forward/backward slashes (&sol;, &bsol;)
                    // - colon (&colon;)
                    // - semicolon (&semi;)
                    '[\x27\x22](?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)',
                    // Pattern 2: Encoded/special characters followed by quote
                    // Same as above but in reverse order - special chars followed by quote
                    '(?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)[\x27\x22]',

                    // Pattern 3: Hexadecimal or decimal HTML entities with semicolon
                    // e.g., &#x27; (hex) or &#39; (decimal)
                    '&#[xX]?[a-f0-9]+;',

                    // Pattern 4: Raw decimal HTML entities
                    // e.g., &#60 (without semicolon)
                    '&#\d+',

                    // Pattern 5: URL encoded characters
                    // e.g., %3C for <, %3E for >, %22 for ", %27 for '
                    '%[a-f0-9]{2}',

                    // Pattern 6: Unicode/hex escapes
                    // e.g., \u003C for <, \x3C for
                    '\\[xXuU][a-f0-9]{4}',
                    // New patterns for this type of payload
                    '</[^>]+/[^>]+>', // Matches closing tags with slash delimiters
                    '//[^"\x27>\s]+', // Matches protocol-relative URLs
                    'xss\.report', // Specific known XSS domains
                    '/\*|\*/|\-\->', // comment chars (/*, */, -->)
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
      or (
        strings.icontains(sender.display_name, "via")
        and any(headers.hops,
                any(.fields,
                    .name == "List-ID"
                    and strings.ends_with(.value,
                                          strings.concat(sender.email.domain.domain,
                                                         ">"
                                          )
                    )
                )
        )
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

Detection logic

Scope: inbound message.

This rule detects Cross-Site Scripting (XSS) attempts within email subjects. It bypasses messages from highly trusted domains unless they fail authentication. However, the rule remains flexible, triggering even for trusted domains when emails are sent from Google Groups, ensuring thorough protection against potential threats while minimizing false positives.

  1. inbound message
  2. subject.subject matches any of 2 patterns
    • (?:[<]|%(25)?3c|\\u003c|\\x3c|&[lg]t;|&n[vw][lg]t;)\/?(?:script(?:\s*/?\s*src\s*=)?|div|iframe|embed|object|style|form|meta|link|svg|img|audio|video|source|body|input|textarea|select|noscript|(?:/|%(25)?2f)?title|(?:/|%(25)?2f)?textarea|(?:/|%(25)?2f)?style|(?:/|%(25)?2f)?template|(?:/|%(25)?2f)?noembed)
    • constructor\.constructor|\[\s*constructor\s*\]|\.__proto__|\[constructor\]
  3. subject.subject matches any of 3 patterns
    • (?:\b|%[a-f0-9]{2})(?:on(?:abort|blur|change|click|dblclick|error|focus|load|mouse(?:over|out|move|down|up)|key(?:down|up|press)|reset|select|submit|unload)|srcdoc|src\s*(?:=|%(?:25)?3d))
    • (?:\b|%(?:25)?[a-f0-9]{2})(?:javascript|eval|settimeout|setinterval|document\.(?:cookie|write|location|createElement|body|appendChild)|fetch|constructor|__proto__|prototype|atob|getScript|script(?:\s|%(?:25)?20)src)(?:\b|%(?:25)?[a-f0-9]{2})
    • (?:\b|%(?:25)?[a-f0-9]{2})script(?:\s|%(?:25)?20)src(?:\b|%(?:25)?[a-f0-9]{2})
  4. subject.subject matches any of 10 patterns
    • [\x27\x22](?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)
    • (?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)[\x27\x22]
    • &#[xX]?[a-f0-9]+;
    • &#\d+
    • %[a-f0-9]{2}
    • \\[xXuU][a-f0-9]{4}
    • </[^>]+/[^>]+>
    • //[^"\x27>\s]+
    • xss\.report
    • /\*|\*/|\-\->
  5. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • any of:
        • any of distinct(headers.hops) where:
          • .authentication_results.dmarc matches '*fail'
        • all of:
          • sender.display_name contains 'via'
          • any of headers.hops where:
            • any of .fields where all hold:
              • .name is 'List-ID'
              • strings.ends_with(.value)
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains

Inspects: headers.hops, headers.hops[].authentication_results.dmarc, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, sender.display_name, sender.email.domain.domain, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: regex.icontains, strings.concat, strings.ends_with, strings.icontains, strings.ilike. Reference lists: $high_trust_sender_root_domains.

Indicators matched (18)

FieldMatchValue
regex.icontainsregex(?:[<]|%(25)?3c|\\u003c|\\x3c|&[lg]t;|&n[vw][lg]t;)\/?(?:script(?:\s*/?\s*src\s*=)?|div|iframe|embed|object|style|form|meta|link|svg|img|audio|video|source|body|input|textarea|select|noscript|(?:/|%(25)?2f)?title|(?:/|%(25)?2f)?textarea|(?:/|%(25)?2f)?style|(?:/|%(25)?2f)?template|(?:/|%(25)?2f)?noembed)
regex.icontainsregexconstructor\.constructor|\[\s*constructor\s*\]|\.__proto__|\[constructor\]
regex.icontainsregex(?:\b|%[a-f0-9]{2})(?:on(?:abort|blur|change|click|dblclick|error|focus|load|mouse(?:over|out|move|down|up)|key(?:down|up|press)|reset|select|submit|unload)|srcdoc|src\s*(?:=|%(?:25)?3d))
regex.icontainsregex(?:\b|%(?:25)?[a-f0-9]{2})(?:javascript|eval|settimeout|setinterval|document\.(?:cookie|write|location|createElement|body|appendChild)|fetch|constructor|__proto__|prototype|atob|getScript|script(?:\s|%(?:25)?20)src)(?:\b|%(?:25)?[a-f0-9]{2})
regex.icontainsregex(?:\b|%(?:25)?[a-f0-9]{2})script(?:\s|%(?:25)?20)src(?:\b|%(?:25)?[a-f0-9]{2})
regex.icontainsregex[\x27\x22](?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)
regex.icontainsregex(?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)[\x27\x22]
regex.icontainsregex&#[xX]?[a-f0-9]+;
regex.icontainsregex&#\d+
regex.icontainsregex%[a-f0-9]{2}
regex.icontainsregex\\[xXuU][a-f0-9]{4}
regex.icontainsregex</[^>]+/[^>]+>
6 more
regex.icontainsregex//[^"\x27>\s]+
regex.icontainsregexxss\.report
regex.icontainsregex/\*|\*/|\-\->
strings.ilikesubstring*fail
strings.icontainssubstringvia
headers.hops[].fields[].nameequalsList-ID

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        and
          any(headers.hops)
            any(headers.hops.fields)
              and
                headers.hops.fields[].name eq "List-ID"
                strings.ends_with func_call "strings.ends_with(headers.hops[].fields[].value)"
          sender.display_name contains "via"
        any(distinct(headers.hops))
          distinct(headers.hops).authentication_results.dmarc ends_with "fail"
       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
    subject.subject regex_match "%[a-f0-9]{2}"
    subject.subject regex_match "&#[xX]?[a-f0-9]+;"
    subject.subject regex_match "&#\\d+"
    subject.subject regex_match "(?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\\x3b)[\\x27\\x22]"
    subject.subject regex_match "//[^\"\\x27>\\s]+"
    subject.subject regex_match "/\\*|\\*/|\\-\\->"
    subject.subject regex_match "</[^>]+/[^>]+>"
    subject.subject regex_match "[\\x27\\x22](?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\\x3b)"
    subject.subject regex_match "\\\\[xXuU][a-f0-9]{4}"
    subject.subject regex_match "xss\\.report"
  or
    subject.subject regex_match "(?:[<]|%(25)?3c|\\\\u003c|\\\\x3c|&[lg]t;|&n[vw][lg]t;)\\/?(?:script(?:\\s*/?\\s*src\\s*=)?|div|iframe|embed|object|style|form|meta|link|svg|img|audio|video|source|body|input|textarea|select|noscript|(?:/|%(25)?2f)?title|(?:/|%(25)?2f)?textarea|(?:/|%(25)?2f)?style|(?:/|%(25)?2f)?template|(?:/|%(25)?2f)?noembed)"
    subject.subject regex_match "constructor\\.constructor|\\[\\s*constructor\\s*\\]|\\.__proto__|\\[constructor\\]"
  or
    subject.subject regex_match "(?:\\b|%(?:25)?[a-f0-9]{2})(?:javascript|eval|settimeout|setinterval|document\\.(?:cookie|write|location|createElement|body|appendChild)|fetch|constructor|__proto__|prototype|atob|getScript|script(?:\\s|%(?:25)?20)src)(?:\\b|%(?:25)?[a-f0-9]{2})"
    subject.subject regex_match "(?:\\b|%(?:25)?[a-f0-9]{2})script(?:\\s|%(?:25)?20)src(?:\\b|%(?:25)?[a-f0-9]{2})"
    subject.subject regex_match "(?:\\b|%[a-f0-9]{2})(?:on(?:abort|blur|change|click|dblclick|error|focus|load|mouse(?:over|out|move|down|up)|key(?:down|up|press)|reset|select|submit|unload)|srcdoc|src\\s*(?:=|%(?:25)?3d))"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
sender.display_namecontains
  • via
field:"sender.display_name" kind:contains value:"via"
subject.subjectregex_match
  • %[a-f0-9]{2}
  • &#[xX]?[a-f0-9]+;
  • &#\d+
  • (?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)[\x27\x22]
  • (?:[<]|%(25)?3c|\u003c|\x3c|&[lg]t;|&n[vw][lg]t;)\/?(?:script(?:\s*/?\s*src\s*=)?|div|iframe|embed|object|style|form|meta|link|svg|img|audio|video|source|body|input|textarea|select|noscript|(?:/|%(25)?2f)?title|(?:/|%(25)?2f)?textarea|(?:/|%(25)?2f)?style|(?:/|%(25)?2f)?template|(?:/|%(25)?2f)?noembed)
  • (?:\b|%(?:25)?[a-f0-9]{2})(?:javascript|eval|settimeout|setinterval|document.(?:cookie|write|location|createElement|body|appendChild)|fetch|constructor|__proto__|prototype|atob|getScript|script(?:\s|%(?:25)?20)src)(?:\b|%(?:25)?[a-f0-9]{2})
  • (?:\b|%(?:25)?[a-f0-9]{2})script(?:\s|%(?:25)?20)src(?:\b|%(?:25)?[a-f0-9]{2})
  • (?:\b|%[a-f0-9]{2})(?:on(?:abort|blur|change|click|dblclick|error|focus|load|mouse(?:over|out|move|down|up)|key(?:down|up|press)|reset|select|submit|unload)|srcdoc|src\s*(?:=|%(?:25)?3d))
  • //[^"\x27>\s]+
    • /*
    • */
    • \-\->
  • </[^>]+/[^>]+>
  • [\x27\x22](?:%3[CE]|[<>]|&(?:lt|gt|quot|apos|[lr](?:par|cub|sqb)|equals|[bs]ol|colon|semi)\x3b)
  • \[xXuU][a-f0-9]{4}
    • constructor.constructor
    • [\s*constructor\s*]
    • .__proto__
    • [constructor]
  • xss.report
field:"subject.subject" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"