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) == 0
  3. any of:
    • all of:
      • (0) < (length(body.links))
      • (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(distinct(headers.hops, .authentication_results.dmarc is not null), strings.ilike(.authentication_results.dmarc, "*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
      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"
  or
    and
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
       macro "(\n      any(distinct(headers.hops, .authentication_results.dmarc is not null),\n          strings.ilike(.authentication_results.dmarc, \"*fail\")\n      )\n    )"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  attachments length_compare "0"
  type.inbound eq "true"

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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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"

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:
      • (0) < (length(body.current_thread.links))
      • (length(body.current_thread.links)) < (10)
    • length(body.current_thread.links) > 100
  3. any([subject.subject, sender.display_name], regex.icontains(., "(?:cloud|storage|mailbox|account|system|service|^data)" ) )
  4. any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents, .name == "cred_theft" and .confidence == "high" )
  5. not:
    • any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics, .name == "Customer Service and Support" and .confidence == "high" )
  6. 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" )
  7. not:
    • strings.ilike(beta.ocr(file.message_screenshot()).text, "*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") != 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(.href_url.domain.root_domain, \"null\") != coalesce(sender.email.domain.root_domain,\n                                                                         \"\"\n          )"
        body.current_thread.links.href_url.domain.root_domain eq "beehiiv.com"
        body.current_thread.links.href_url.domain.root_domain macro "body.current_thread.links[].href_url.domain.root_domain in free_file_hosts"
        body.current_thread.links.href_url.domain.root_domain macro "body.current_thread.links[].href_url.domain.root_domain in url_shorteners"
        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(.href_url.domain).days_old < 365"
      body.current_thread.links.display_text is_null
      body.current_thread.links.display_url.url is_null
      body.current_thread.links.href_url.domain.domain macro "body.current_thread.links[].href_url.domain.domain not in tenant_domains"
  or
    and
      not
        headers.auth_summary.dmarc.pass eq "true"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  or
    and
      body.current_thread.links length_compare "0"
      body.current_thread.links length_compare "10"
    body.current_thread.links length_compare "100"
  not
    strings.ilike func_call "strings.ilike(beta.ocr(file.message_screenshot()).text, \"*free plan*\")"
  not
     macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,\n            .name == \"Customer Service and Support\" and .confidence == \"high\"\n)"
  regex.icontains func_call "regex.icontains(beta.ocr(file.message_screenshot()).text,\n                    \"storage.{0,50}full\",\n                    \"free.{0,50}upgrade\",\n                    \"storage.{0,50}details\",\n                    \"storage.{0,50}quot\",\n                    \"(?:mailbox|account|cloud).{0,50}(?:at risk|storage|disabled)\",\n                    '\\d{2}%\\s*capacity',\n                    \"data.{0,20}(?:removal|purge|protection mode)\",\n                    \"billing.{0,20}suspended\"\n)"
  type.inbound eq "true"
   macro "any([subject.subject, sender.display_name],\n        regex.icontains(.,\n                        \"(?:cloud|storage|mailbox|account|system|service|^data)\"\n        )\n)"
   macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,\n        .name == \"cred_theft\" and .confidence == \"high\"\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
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, recipients.to[0].email.email)

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(.href_url.fragment, recipients.to[0].email.email)"
  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.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Credential Phishing: Bitcoin portfolio confirmation

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

Detects inbound messages that combine bitcoin/BTC terminology with portfolio or balance confirmation language, alongside at least two credential-harvesting indicators such as references to a web portal, customer ID, or password. The rule further requires the NLU classifier to flag the message with credential theft, advance fee, or BEC intent, and excludes messages from senders on high trust root domains that pass DMARC authentication.

Threat Classification

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

CategoryValues
Attack typesCredential Phishing, BEC/Fraud
Tactics and techniquesSocial engineering

Telemetry Coverage

PlatformRecord / event type
SublimeInbound email message

Message Attributes

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

Rule Body

type.inbound
and (
  strings.icontains(body.current_thread.text, "btc", "bitcoin")
  or regex.icontains(body.current_thread.text, 'pass[\s-]?word')
)
and 2 of (
  strings.icontains(body.current_thread.text, "portfolio"),
  strings.icontains(body.current_thread.text, "confirm your balance"),
  strings.icontains(body.current_thread.text, "web portal"),
  strings.icontains(body.current_thread.text, "customer id"),
  strings.icontains(body.current_thread.text, "login to confirm")
)
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name in ("cred_theft", "advance_fee", "bec")
)
// and the sender is not from high trust sender root domains
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 that combine bitcoin/BTC terminology with portfolio or balance confirmation language, alongside at least two credential-harvesting indicators such as references to a web portal, customer ID, or password. The rule further requires the NLU classifier to flag the message with credential theft, advance fee, or BEC intent, and excludes messages from senders on high trust root domains that pass DMARC authentication.

  1. inbound message
  2. any of:
    • body.current_thread.text contains any of 2 patterns
      • btc
      • bitcoin
    • body.current_thread.text matches 'pass[\\s-]?word'
  3. at least 2 of 5: body.current_thread.text contains any of 5 patterns
    • portfolio
    • confirm your balance
    • web portal
    • customer id
    • login to confirm
  4. any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("cred_theft", "advance_fee", "bec") )
  5. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass, false)

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.icontains. Reference lists: $high_trust_sender_root_domains.

Indicators Matched (11)

FieldMatchValue
strings.icontainssubstringbtc
strings.icontainssubstringbitcoin
regex.icontainsregexpass[\s-]?word
strings.icontainssubstringportfolio
strings.icontainssubstringconfirm your balance
strings.icontainssubstringweb portal
strings.icontainssubstringcustomer id
strings.icontainssubstringlogin to confirm
ml.nlu_classifier(body.current_thread.text).intents[].namemembercred_theft
ml.nlu_classifier(body.current_thread.text).intents[].namememberadvance_fee
ml.nlu_classifier(body.current_thread.text).intents[].namememberbec

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      body.current_thread.text contains "confirm your balance"
      body.current_thread.text contains "customer id"
    and
      body.current_thread.text contains "confirm your balance"
      body.current_thread.text contains "login to confirm"
    and
      body.current_thread.text contains "confirm your balance"
      body.current_thread.text contains "portfolio"
    and
      body.current_thread.text contains "confirm your balance"
      body.current_thread.text contains "web portal"
    and
      body.current_thread.text contains "customer id"
      body.current_thread.text contains "login to confirm"
    and
      body.current_thread.text contains "customer id"
      body.current_thread.text contains "portfolio"
    and
      body.current_thread.text contains "customer id"
      body.current_thread.text contains "web portal"
    and
      body.current_thread.text contains "login to confirm"
      body.current_thread.text contains "portfolio"
    and
      body.current_thread.text contains "login to confirm"
      body.current_thread.text contains "web portal"
    and
      body.current_thread.text contains "portfolio"
      body.current_thread.text contains "web portal"
  not
    and
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  or
    body.current_thread.text contains "bitcoin"
    body.current_thread.text contains "btc"
    body.current_thread.text regex_match "pass[\\s-]?word"
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n        .name in (\"cred_theft\", \"advance_fee\", \"bec\")\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • bitcoin corpus 3 (mql 3)
  • btc
  • confirm your balance
  • customer id
  • login to confirm
  • portfolio
  • web portal
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • pass[\s-]?word
field:"body.current_thread.text" kind:regex_match value:"pass[\s-]?word"
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.dmarc.passis_not_null(no value, null check)excludes:headers.auth_summary.dmarc.pass

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) == 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:
      • strings.ilike(beta.ocr(file.message_screenshot()).text, "*DocuSign*")
      • any(ml.logo_detect(file.message_screenshot()).brands, .name == "DocuSign" )
    • any of:
      • all of:
        • any of:
          • 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)", )
          • 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:
          • regex.icontains(strings.replace_confusables(.display_text), '(\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, false )

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,\n                             \"(wichtig|dringend|sofort)\"\n            ) > 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,\n                             \"(wichtig|dringend|sofort)\"\n            ) > 1"
        regex.icontains func_call "regex.icontains(beta.ocr(file.message_screenshot()).text,\n                        \"((re)?view|access|sign|complete(d)?) documen(t)?(s)?\",\n                        \"Your document has been completed\",\n                        \"New Document Shared with you\",\n                        \"Kindly click the link\",\n                        \"important edocs\",\n                        // German (Document (check|check|sign|sent))\n                        \"Dokument (überprüfen|prüfen|unterschreiben|geschickt)\",\n        )"
      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}"
          regex.icontains func_call "regex.icontains(strings.replace_confusables(.display_text),\n                             '(\\bdocument|(view|get your) (docu|file))'\n             )"
        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"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain 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, .size < 8000 and .file_type in $file_types_images)"
    attachments length_compare "0"
  not
    or
      headers.in_reply_to is_not_null
      headers.references length_compare "0"
  not
    coalesce func_call "coalesce(headers.auth_summary.dmarc.pass\n               and strings.contains(sender.display_name, \"via\")\n               and sender.email.domain.domain in $org_domains,\n               false\n  )"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  or
    strings.ilike func_call "strings.ilike(beta.ocr(file.message_screenshot()).text, \"*DocuSign*\")"
     macro "any(ml.logo_detect(file.message_screenshot()).brands,\n           .name == \"DocuSign\"\n    )"
  length func_call "length(filter(body.links, .href_url.domain.valid)) < 25"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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"

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(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence == "high" )
    • all of:
      • length(body.current_thread.text) < 250
      • any of recipients.to where any holds:
        • strings.icontains(body.current_thread.text, .email.domain.sld)
        • strings.icontains(body.current_thread.text, .email.local_part)
  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"
        body.links.href_url.domain.root_domain macro "body.links[].href_url.domain.root_domain not in org_domains"
        body.links.href_url.domain.root_domain macro "body.links[].href_url.domain.root_domain not in tranco_50k"
     macro "(all(recipients.to, .email.local_part == sender.display_name))"
  or
    and
      or
        not
          and
            headers.auth_summary.dmarc.pass is_null
            headers.message_id ends_with "protection.outlook.com>"
             macro "all(headers.domains,\n                .root_domain in (\"outlook.com\", \"office365.com\")\n        )"
        not
          headers.auth_summary.dmarc.pass eq "true"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in org_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in org_domains"
  or
    and
      any(recipients.to)
        or
          strings.icontains func_call "strings.icontains(body.current_thread.text, .email.domain.sld)"
          strings.icontains func_call "strings.icontains(body.current_thread.text, .email.local_part)"
      body.current_thread.text length_compare "250"
     macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n      .name == \"cred_theft\" and .confidence == \"high\"\n  )"
  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"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  or
    and
      body.current_thread.text length_compare "700"
      body.current_thread.text match "mail"
    subject.subject regex_match "(e)?mail(s)?"
  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"
   macro "3 of (\n  strings.ilike(body.current_thread.text, \"*incoming messages*\"),\n  strings.ilike(body.current_thread.text, \"*server error*\"),\n  strings.ilike(body.current_thread.text, \"*blocked*\"),\n  strings.ilike(body.current_thread.text, \"*prevented*\"),\n  strings.ilike(body.current_thread.text, \"*notification*\"),\n  strings.ilike(body.current_thread.text, \"*fix email issues*\"),\n  strings.ilike(body.current_thread.text, \"*rejected*\"),\n  strings.ilike(body.current_thread.text, \"*recover and prevent*\"),\n  strings.ilike(body.current_thread.text, \"*failure*\"),\n  strings.ilike(body.current_thread.text, \"*rejection*\"),\n  strings.ilike(body.current_thread.text, \"*failed*\")\n)"

Indicators

These rows show field, operator, and value matches.

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

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(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence == "high" )
  5. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass, false)

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
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  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"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n        .name == \"cred_theft\" and .confidence == \"high\"\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • \bcard\b
field:"body.current_thread.text" kind:regex_match value:"\bcard\b"
body.current_thread.textwildcard
  • *collect bank details*
  • *could be with you*
  • *currently accessible*
  • *not a financial institution*
field:"body.current_thread.text" kind:wildcard
subject.baseregex_match
  • \bcard\b
field:"subject.base" kind:regex_match value:"\bcard\b"
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.dmarc.passis_not_null(no value, null check)excludes:headers.auth_summary.dmarc.pass

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 == "english"
  6. not:
    • any(ml.nlu_classifier(body.current_thread.text).topics, .name in ("Health and Wellness", "Entertainment and Sports") and .confidence == "high" )
  7. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass, false)

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
    and
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain 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
    length func_call "length(html.xpath(body.html, '//a/img').nodes) > 0"
    length func_call "length(html.xpath(body.html,\n                    '//*[contains(@style, \"background\") and contains(@style, \"padding\")] | //a[contains(@class, \"es-button\")]'\n         ).nodes\n  ) > 0"
  not
     macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n            .name in (\"Health and Wellness\", \"Entertainment and Sports\")\n            and .confidence == \"high\"\n)"
  headers.mailer contains "ActiveCampaign"
  ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language == \"english\""
  type.inbound eq "true"

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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.dmarc.passis_not_null(no value, null check)excludes:headers.auth_summary.dmarc.pass

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(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, " ", .) ) ) )
    • ( // 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, .) ) ) ) )
    • 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") ) )
    • 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
    • any(ml.nlu_classifier(body.current_thread.text).entities, .name == "recipient" and regex.icontains(.text, '[{}]') )
  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(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")
  6. not:
    • any(ml.nlu_classifier(body.current_thread.text).topics, .name in ("Software and App Updates", "B2B Cold Outreach") )
  7. not:
    • all of:
      • length(recipients.to) == 1
      • all of:
        • any of:
          • length(recipients.cc) != 0
          • length(recipients.bcc) != 0
        • not:
          • any of recipients.bcc where:
            • .email.local_part is 'notifications'
      • none of:
        • length(recipients.to) == 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, false)
    • 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, false)

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
    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})"
  or
    and
      not
        and
          headers.auth_summary.dmarc.pass eq "true"
          headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  not
    and
      not
        any(recipients.bcc)
          recipients.bcc.email.local_part eq "notifications"
      not
        or
          recipients.to length_compare "0"
           macro "all(recipients.to, .email.domain.valid == false)"
      or
        recipients.bcc length_compare "0"
        recipients.cc length_compare "0"
      recipients.to length_compare "1"
  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
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain in ["gc.ai", "getguru.com", "glean.com", "mentorloop.com"]
  not
    body.current_thread.text regex_match "meeting (?:note|recap)|daily brief|brief recap"
  or
    length func_call "length(filter([\n                     recipients.to[0].email.domain.sld,\n                     recipients.to[0].email.local_part,\n                     recipients.to[0].email.domain.domain,\n                     // \"firstlast\" naming convention observed\n                     strings.concat(mailbox.first_name, mailbox.last_name)\n                   ],\n                   strings.icontains(body.current_thread.text, .)\n            )\n  ) >= 2"
     macro "(\n    // nlu capture for wide scope of greetings to reduce evasion\n    any(filter(ml.nlu_classifier(body.current_thread.text).entities,\n               .name == \"greeting\"\n        ),\n        // nlu capture for wide scope of recipient entity to reduce evasion\n        any(filter(ml.nlu_classifier(body.current_thread.text).entities,\n                   .name == \"recipient\"\n                   and not (\n                     strings.icontains(.text, \"customer\")\n                     // accounting for grouped recipients\n                     or regex.icontains(.text, '&|\\band\\b')\n                   )\n            ),\n            // recipient entity follows the greeting in the body text\n            strings.icontains(body.current_thread.text,\n                              strings.concat(..text, \" \", .text)\n            )\n            // the named recipient doesn't match the actual \"to\" recipient\n            and not any([\n                          recipients.to[0].email.domain.sld,\n                          recipients.to[0].email.local_part,\n                          recipients.to[0].email.domain.domain,\n                          mailbox.first_name,\n                        ],\n                        strings.icontains(..text, .)\n            )\n        )\n    )\n  )"
     macro "any([\n           recipients.to[0].email.domain.sld,\n           recipients.to[0].email.local_part,\n           recipients.to[0].email.domain.domain,\n           // \"firstlast\" naming convention observed\n           strings.concat(mailbox.first_name, mailbox.last_name)\n         ],\n         // strings logic for non-greeting body starter\n         strings.icontains(body.current_thread.text,\n                           strings.concat(\"attn: \", .)\n         )\n         // strings logic for recipient as body starter\n         or strings.icontains(body.current_thread.text,\n                              strings.concat(., \" balance statement\")\n         )\n  )"
     macro "any(filter(ml.nlu_classifier(body.current_thread.text).entities,\n             .name == \"greeting\"\n      ),\n      any([\n            recipients.to[0].email.domain.sld,\n            recipients.to[0].email.local_part,\n            recipients.to[0].email.domain.domain,\n            // \"firstlast\" naming convention observed\n            strings.concat(mailbox.first_name, mailbox.last_name)\n          ],\n          // recipient entity follows the greeting in the body text\n          strings.icontains(body.current_thread.text,\n                            strings.concat(..text, \" \", .)\n          )\n      )\n  )"
     macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n         .name == \"recipient\" and regex.icontains(.text, '[{}]')\n  )"
  not
     macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n            .name in (\"Software and App Updates\", \"B2B Cold Outreach\")\n)"
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents, .name != \"benign\")"

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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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"
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.dmarc.passis_not_null(no value, null check)excludes:headers.auth_summary.dmarc.pass
sender.email.domain.root_domainingc.ai, getguru.com, glean.com, mentorloop.comexcludes:sender.email.domain.root_domain
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"

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) == 1
      • length(recipients.cc) == 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([subject.base], strings.icontains(sender.email.domain.sld, .))
    • all of:
      • any of:
        • length(subject.base) == 0
        • subject.base is missing
      • any of recipients.to where:
        • strings.istarts_with(body.current_thread.text, .email.domain.sld)
  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:
        • 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' )
        • strings.icontains(beta.ocr(file.message_screenshot()).text, 'document I sent' )
        • strings.icontains(beta.ocr(file.message_screenshot()).text, 'proposal document' )
        • strings.icontains(beta.ocr(file.message_screenshot()).text, 'let me know what you think' )
  5. 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/') )
  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 == false
    • profile.by_sender_email().prevalence == "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, false)
  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
  or
    and
      not
        or
          and
            headers.auth_summary.dmarc.pass eq "true"
            headers.auth_summary.dmarc.pass is_not_null
          headers.auth_summary.spf.pass eq "true"
      sender.email.domain.domain 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
      not
        headers.auth_summary.dmarc.pass eq "true"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  or
    and
      or
        regex.icontains func_call "regex.icontains(beta.ocr(file.message_screenshot()).text,\n                      '\\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'\n      )"
        strings.icontains func_call "strings.icontains(beta.ocr(file.message_screenshot()).text,\n                           'document I sent'\n      )"
        strings.icontains func_call "strings.icontains(beta.ocr(file.message_screenshot()).text,\n                           'let me know what you think'\n      )"
        strings.icontains func_call "strings.icontains(beta.ocr(file.message_screenshot()).text,\n                           'proposal document'\n      )"
      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
      any(recipients.to)
        strings.istarts_with func_call "strings.istarts_with(body.current_thread.text, .email.domain.sld)"
      or
        subject.base is_null
        subject.base length_compare "0"
    and
      length func_call "length(subject.base) < length(sender.email.domain.sld)"
       macro "any([subject.base], strings.icontains(sender.email.domain.sld, .))"
    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"
   macro "any(filter(body.links,\n               // display text looks like a file\n               (\n                 regex.icontains(.display_text,\n                                 '\\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)'\n                 )\n                 or regex.icontains(.display_text, '\\d+kb|\\d+mb')\n                 or strings.icontains(.display_text, 'document')\n                 or strings.icontains(.display_text, 'proposal')\n                 or strings.icontains(.display_text, 'review')\n                 // account for image-as-content\n                 or (\n                   length(body.current_thread.text) < 10\n                   and length(body.links) == 1\n                 )\n               )\n               // but the URL doesn't point to legitimate file sharing\n               and .href_url.domain.root_domain not in (\n                 \"sharepoint.com\",\n                 \"google.com\",\n                 \"dropbox.com\",\n                 \"box.com\",\n                 \"onedrive.com\",\n                 \"1drv.ms\",\n                 \"aka.ms\",\n                 \"microsoft.com\",\n                 \"office.com\",\n                 \"docusign.com\",\n                 \"adobesign.com\",\n                 \"hellosign.com\",\n                 \"signable.app\"\n               )\n               and .href_url.domain.domain not in (\"drive.google.com\")\n        ),\n        // and points to suspicious domains\n        .href_url.domain.tld in $suspicious_tlds\n        or .href_url.domain.root_domain in $url_shorteners\n        or .href_url.domain.domain in $url_shorteners\n        or .href_url.domain.root_domain in $free_file_hosts\n        or .href_url.domain.domain in $free_file_hosts\n        // or it's a forms/survey platform being abused in self_service_creation_platform_domains\n        or .href_url.domain.root_domain in $self_service_creation_platform_domains\n        or .href_url.domain.domain in $self_service_creation_platform_domains\n        // bulk mailer abuse has been observed\n        or (\n          (\n            .href_url.domain.root_domain in $bulk_mailer_url_root_domains\n            or (\n              .href_url.rewrite.original is not null\n              and 'mandrill' in .href_url.rewrite.encoders\n            )\n          )\n          and .href_url.domain.sld not in $org_slds\n        )\n        // or the page redirects to common website, observed when evasion happens\n        or (\n          length(ml.link_analysis(., mode=\"aggressive\").redirect_history) > 0\n          and ml.link_analysis(., mode=\"aggressive\").effective_url.domain.root_domain in $tranco_10k\n        )\n        // or common email marketing/tracking patterns\n        or regex.match(.href_url.url, 'url\\d+\\..*\\.com/ls/click')\n        or regex.match(.href_url.path, '/ls/click|/click|/c/')\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
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"
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 corpus 1212 (mql 1212)
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:
    • (0) < (length(attachments))
    • (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:
        • (0) <= ((length(body.current_thread.text)))
        • ((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, sender.email.email)
          • 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(distinct(headers.hops, .authentication_results.dmarc is not null), strings.ilike(.authentication_results.dmarc, "*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(distinct(headers.hops, .authentication_results.dmarc is not null), strings.ilike(.authentication_results.dmarc, "*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, sender.email.email)"
        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
  any(body.links)
    and
      body.links.display_text is_null
      body.links.display_url.url is_null
      body.links.href_url.domain.root_domain 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"
  not
    and
      sender.display_name contains "via Canva"
      sender.email.domain.domain eq "canva.com"
       macro "(\n    any(distinct(headers.hops, .authentication_results.dmarc is not null),\n        strings.ilike(.authentication_results.dmarc, \"*pass\")\n    )\n  )"
  or
    and
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
       macro "(\n      any(distinct(headers.hops, .authentication_results.dmarc is not null),\n          strings.ilike(.authentication_results.dmarc, \"*fail\")\n      )\n    )"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  attachments length_compare "0"
  attachments length_compare "8"
  body.links length_compare "0"
  type.inbound eq "true"
   macro "all(attachments, .file_type in $file_types_images and .size > 2000)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • caution corpus 3 (mql 3)
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
    corpus 2 (mql 2)
field:"body.current_thread.text" kind:regex_match
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

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:
        • (0) < (strings.ilevenshtein(strings.replace_confusables(sender.display_name), "one?drive" ))
        • (strings.ilevenshtein(strings.replace_confusables(sender.display_name), "one?drive" )) < (2)
      • any of attachments where any holds:
        • all of:
          • .file_name matches '[0o]ne\\s?dr[il1]ve'
          • 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." ) )
        • all of:
          • .file_type is 'pdf'
          • any(ml.logo_detect(.).brands, .name == "Microsoft")
          • any(file.explode(.), any(.scan.strings.strings, strings.icontains(., "shared a file") ) )
    • regex.imatch(strings.replace_confusables(body.current_thread.text), '[0o]ne\s?dr[il1]ve.*' )
    • all of:
      • regex.icontains(strings.replace_confusables(subject.subject), '[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(ml.nlu_classifier(body.current_thread.text).topics, .name == "File Sharing and Cloud Services" and .confidence == "high" )
      • ratio(filter(body.links, .display_text is not null), regex.icontains(.display_text, '[0o]ne\s?dr[il1]ve') ) > 0.5
    • all of:
      • any of body.current_thread.links where all hold:
        • any(ml.logo_detect(ml.link_analysis(.).screenshot).brands, .name == "Microsoft OneDrive" and .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(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence in ("medium", "high") )
    • any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents, .name == "cred_theft" and .confidence in ("medium", "high") )
    • any of body.current_thread.links where:
      • ml.link_analysis(.).credphish.disposition == "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, false)
  6. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass, false)
  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
    and
      or
        any(body.links)
          and
            body.links.href_url.domain.root_domain macro "body.links[].href_url.domain.root_domain in free_subdomain_hosts"
            body.links.href_url.domain.subdomain is_not_null
            body.links.href_url.domain.subdomain ne "www"
        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)"
      regex.icontains func_call "regex.icontains(strings.replace_confusables(subject.subject),\n                    '[0o]ne\\s?dr[il1]ve'\n    )"
    any(attachments)
      or
        and
          not
             macro "any(file.explode(.),\n                         any(.scan.exiftool.fields,\n                             .key == \"Model\"\n                             or (\n                               .key == \"Software\"\n                               and strings.starts_with(.value, \"Android\")\n                             )\n                         )\n                         // exclude images taken with mobile cameras and screenshots from Apple\n                         or any(.scan.exiftool.fields,\n                                .key == \"DeviceManufacturer\"\n                                and .value == \"Apple Computer Inc.\"\n                         )\n             )"
          attachments.file_name regex_match "[0o]ne\\s?dr[il1]ve"
        and
          attachments.file_type eq "pdf"
           macro "any(file.explode(.),\n                     any(.scan.strings.strings,\n                         strings.icontains(., \"shared a file\")\n                     )\n             )"
           macro "any(ml.logo_detect(.).brands, .name == \"Microsoft\")"
    and
      any(body.current_thread.links)
        and
          ml.link_analysis func_call "ml.link_analysis(.).effective_url.domain.root_domain in $free_subdomain_hosts"
           macro "any(ml.logo_detect(ml.link_analysis(.).screenshot).brands,\n            .name == \"Microsoft OneDrive\" and .confidence in (\"medium\", \"high\")\n        )"
      body.current_thread.text regex_match "[0o]ne\\s?dr[il1]ve"
    and
      ratio func_call "ratio(filter(body.links, .display_text is not null),\n              regex.icontains(.display_text, '[0o]ne\\s?dr[il1]ve')\n    ) > 0.5"
       macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n        .name == \"File Sharing and Cloud Services\" and .confidence == \"high\"\n    )"
    and
      strings.ilevenshtein func_call "(0) < (strings.ilevenshtein(strings.replace_confusables(sender.display_name),\n                                \"one?drive\"\n    ))"
      strings.ilevenshtein func_call "(strings.ilevenshtein(strings.replace_confusables(sender.display_name),\n                                \"one?drive\"\n    )) < (2)"
    regex.imatch func_call "regex.imatch(strings.replace_confusables(body.current_thread.text),\n                  '[0o]ne\\s?dr[il1]ve.*'\n  )"
    sender.display_name regex_match "[0o]ne\\s?dr[il1]ve"
    sender.email.local_part 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"
  not
    and
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      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
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.dmarc.pass is_not_null
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  or
    any(body.current_thread.links)
      ml.link_analysis func_call "ml.link_analysis(.).credphish.disposition == \"phishing\""
     macro "any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,\n         .name == \"cred_theft\" and .confidence in (\"medium\", \"high\")\n  )"
     macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n      .name == \"cred_theft\" and .confidence in (\"medium\", \"high\")\n  )"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  body.links length_compare "10"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

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"
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.dmarc.passis_not_null(no value, null check)excludes:headers.auth_summary.dmarc.pass
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

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

Indicators

These rows show field, operator, and value matches.

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

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* corpus 2 (mql 2)
  • H?R
  • HR
field:"sender.display_name" kind:wildcard
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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"

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:
    • (0) < (length(filter(body.links, not strings.ilike(.display_text, "*privacy*", "*terms of service*", "Learn why this is important" ) or .display_text is null ) ))
    • (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(ml.nlu_classifier(body.current_thread.text).entities, .name == "request" )
  10. any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial" )
  11. any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency" )
  12. any(ml.nlu_classifier(body.current_thread.text).entities, .name == "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"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain 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 "(\n    all(body.links, .href_url.domain.root_domain == sender.email.domain.domain)\n  )"
  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, .href_url.domain.domain in $free_email_providers)"
  not
     macro "all(body.links,\n            (\n              strings.icontains(.display_text, \"unsubscribe\")\n              and strings.icontains(.href_url.path, \"unsubscribe\")\n            )\n            or (\n              strings.icontains(.display_text, \"deactivate\")\n              and strings.icontains(.href_url.path, \"DeactivateAccount\")\n            )\n)"
  body.current_thread.text length_compare "2000"
  headers.in_reply_to is_null
  length func_call "(0) < (length(filter(body.links,\n                    not strings.ilike(.display_text,\n                                      \"*privacy*\",\n                                      \"*terms of service*\",\n                                      \"Learn why this is important\"\n                    )\n                    or .display_text is null\n             )\n  ))"
  length func_call "(length(filter(body.links,\n                    not strings.ilike(.display_text,\n                                      \"*privacy*\",\n                                      \"*terms of service*\",\n                                      \"Learn why this is important\"\n                    )\n                    or .display_text is null\n             )\n  )) < (5)"
  subject.subject length_compare "100"
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).entities, .name == \"org\")"
   macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n        .name == \"financial\"\n)"
   macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n        .name == \"request\"\n)"
   macro "any(ml.nlu_classifier(body.current_thread.text).entities,\n        .name == \"urgency\"\n)"

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 corpus 8 (mql 8)
  • :completed corpus 8 (mql 8)
  • [il1]{2}mit.*ma[il1]{2} ?bo?x corpus 8 (mql 8)
  • [il][il][il]egai[ -] corpus 8 (mql 8)
  • [li][li][li]ega[li] attempt corpus 8 (mql 8)
  • [ng]-?[io]n .*block corpus 8 (mql 8)
  • [ng]-?[io]n .*cancel corpus 8 (mql 8)
  • [ng]-?[io]n .*deactiv corpus 8 (mql 8)
  • [ng]-?[io]n .*disabl corpus 8 (mql 8)
  • \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 corpus 8 (mql 8)
  • about.your.account corpus 8 (mql 8)
  • acc(ou)?n?t (is )?on ho[li]d corpus 8 (mql 8)
  • acc(ou)?n?t.*terminat corpus 8 (mql 8)
  • acc(oun)?t.*[il1]{2}mitation corpus 8 (mql 8)
  • access.*limitation corpus 8 (mql 8)
  • account (will be )?block corpus 8 (mql 8)
  • account has been limited corpus 4 (mql 4)
  • account v[il]o[li]at corpus 8 (mql 8)
  • account.*de-?activat corpus 8 (mql 8)
  • account.*locked corpus 8 (mql 8)
  • account.*re-verification corpus 8 (mql 8)
  • account.*security corpus 8 (mql 8)
  • account.*suspension corpus 8 (mql 8)
  • account.has.been corpus 8 (mql 8)
  • account.has.expired corpus 8 (mql 8)
  • account.will.be.blocked corpus 8 (mql 8)
  • action required corpus 4 (mql 4)
  • action.*required corpus 8 (mql 8)
  • activity.*acc(oun)?t corpus 8 (mql 8)
  • almost full corpus 4 (mql 4)
  • almost.full corpus 8 (mql 8)
  • apd notifi cation corpus 4 (mql 4)
  • app[li]e.[il]d corpus 8 (mql 8)
  • are you at your desk corpus 4 (mql 4)
  • are you available corpus 4 (mql 4)
  • attached file to docusign corpus 4 (mql 4)
  • authenticate.*account corpus 8 (mql 8)
  • +153 more values (see full rule source)
field:"subject.subject" kind:regex_match
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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:"

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

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
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

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(ml.nlu_classifier(body.current_thread.text).intents, .name == "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*\\("
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n        .name == \"cred_theft\"\n)"

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 corpus 1212 (mql 1212)
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, "*held*"),
  strings.ilike(body.current_thread.text, "*pending*"),
  strings.ilike(body.current_thread.text, "*stuck*"),
  strings.like(body.current_thread.text, "* MX *"),
  regex.icontains(body.current_thread.text, '(?:message|mail)s? on.?hold'),
  regex.icontains(body.current_thread.text,
                  'mail.?account.?(?:suspen|protect|violat)',
                  'account (?:suspen|protect|violat).{1,50}(?:e?.?mail)'
  )
)
and (
  any(body.links,
      regex.icontains(.display_text,
                      "view",
                      "release",
                      "message",
                      "delete",
                      "recover",
                      "SSO",
                      "sign in",
                      "resolve issue"
      )
  )
  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(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence == "high" )
    • all of:
      • length(body.current_thread.text) < 250
      • any of recipients.to where any holds:
        • strings.icontains(body.current_thread.text, .email.domain.sld)
        • strings.icontains(body.current_thread.text, .email.local_part)
  4. not:
    • all of:
      • length(ml.nlu_classifier(body.current_thread.text).topics) == 1
      • any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Financial Communications" and .confidence != "low" )
  5. at least 3 of 18: body.current_thread.text matches any of 18 patterns
    • *review*
    • *incoming*
    • *release*
    • *quarantine*
    • *messages*
    • *server error*
    • *blocked*
    • *prevented*
    • *validation*
    • *notification*
    • *kindly*
    • *held*
    • *pending*
    • *stuck*
    • * MX *
    • (?:message|mail)s? on.?hold
    • mail.?account.?(?:suspen|protect|violat)
    • account (?:suspen|protect|violat).{1,50}(?:e?.?mail)
  6. any of:
    • any of body.links where:
      • .display_text matches any of 8 patterns
        • view
        • release
        • message
        • delete
        • recover
        • SSO
        • sign in
        • resolve issue
    • 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 (28)

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*
16 more
strings.ilikesubstring*kindly*
strings.ilikesubstring*held*
strings.ilikesubstring*pending*
strings.ilikesubstring*stuck*
strings.likesubstring* MX *
regex.icontainsregex(?:message|mail)s? on.?hold
regex.icontainsregexmail.?account.?(?:suspen|protect|violat)
regex.icontainsregexaccount (?:suspen|protect|violat).{1,50}(?:e?.?mail)
regex.icontainsregexview
regex.icontainsregexrelease
regex.icontainsregexmessage
regex.icontainsregexdelete
regex.icontainsregexrecover
regex.icontainsregexSSO
regex.icontainsregexsign in
regex.icontainsregexresolve issue

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 "resolve issue"
        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,\n                .root_domain in (\n                  \"outlook.com\",\n                  \"office365.com\",\n                  \"exchangelabs.com\"\n                )\n        )"
        not
          headers.auth_summary.dmarc.pass eq "true"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in org_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in org_domains"
  or
    and
      any(recipients.to)
        or
          strings.icontains func_call "strings.icontains(body.current_thread.text, .email.domain.sld)"
          strings.icontains func_call "strings.icontains(body.current_thread.text, .email.local_part)"
      body.current_thread.text length_compare "250"
     macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n      .name == \"cred_theft\" and .confidence == \"high\"\n  )"
  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"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  not
    and
      length func_call "length(ml.nlu_classifier(body.current_thread.text).topics) == 1"
       macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n          .name == \"Financial Communications\" and .confidence != \"low\"\n  )"
  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"
   macro "3 of (\n  strings.ilike(body.current_thread.text, \"*review*\"),\n  strings.ilike(body.current_thread.text, \"*incoming*\"),\n  strings.ilike(body.current_thread.text, \"*release*\"),\n  strings.ilike(body.current_thread.text, \"*quarantine*\"),\n  strings.ilike(body.current_thread.text, \"*messages*\"),\n  strings.ilike(body.current_thread.text, \"*server error*\"),\n  strings.ilike(body.current_thread.text, \"*blocked*\"),\n  strings.ilike(body.current_thread.text, \"*prevented*\"),\n  strings.ilike(body.current_thread.text, \"*validation*\"),\n  strings.ilike(body.current_thread.text, \"*notification*\"),\n  strings.ilike(body.current_thread.text, \"*kindly*\"),\n  strings.ilike(body.current_thread.text, \"*held*\"),\n  strings.ilike(body.current_thread.text, \"*pending*\"),\n  strings.ilike(body.current_thread.text, \"*stuck*\"),\n  strings.like(body.current_thread.text, \"* MX *\"),\n  regex.icontains(body.current_thread.text, '(?:message|mail)s? on.?hold'),\n  regex.icontains(body.current_thread.text,\n                  'mail.?account.?(?:suspen|protect|violat)',\n                  'account (?:suspen|protect|violat).{1,50}(?:e?.?mail)'\n  )\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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

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:
    • (0) < (length(body.links))
    • (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, strings.concat("Sender\n", .email.domain.domain) )

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,\n                          strings.concat(\"Sender\\n\", .email.domain.domain)\n        )"
  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"

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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Exclusions

The rule actively suppresses these predicates.

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

Impersonation: Internal corporate services

#

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 != "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
    sender.email.local_part macro "sender.email.local_part in map(recipients.to, .email.local_part)"
    sender.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(distinct(headers.hops, .authentication_results.dmarc is not null), strings.ilike(.authentication_results.dmarc, "*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, strings.concat(sender.email.domain.domain, ">" ) )
    • 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(.value,\n                                          strings.concat(sender.email.domain.domain,\n                                                         \">\"\n                                          )\n                    )"
          sender.display_name contains "via"
         macro "any(distinct(headers.hops, .authentication_results.dmarc is not null),\n          strings.ilike(.authentication_results.dmarc, \"*fail\")\n      )"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain 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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Back to all Sublime MQL rules