Detection rules › Sublime MQL

Sublime MQL rules: sharepoint

Service abuse: File sharing impersonation with external SharePoint links

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

Detects inbound messages claiming to share files or invite access, containing SharePoint or OneDrive links from external domains. The rule identifies suspicious sharing notifications where link display text matches the sender's name rather than a legitimate document name, indicating potential impersonation of legitimate file sharing services.

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
  • subject
  • type

Rule body

type.inbound
and strings.ilike(subject.subject, "*shared*", "*invit*")
and strings.ilike(body.current_thread.text,
                  "*shared a file with you*",
                  "*shared with you*",
                  "*invited you to access a file*"
)
and not strings.ilike(body.current_thread.text, "invited you to edit")
and (
  any(filter(body.current_thread.links,
             .href_url.domain.domain not in $tenant_domains
             and (
               .href_url.domain.root_domain == "sharepoint.com"
               or .href_url.domain.root_domain == "1drv.ms"
               or (
                 .href_url.domain.root_domain == 'mimecastprotect.com'
                 and strings.icontains(.href_url.query_params,
                                       '.sharepoint.com'
                 )
               )
             )
             and .display_text != "Open"
      ),
      // check if the display_text exactly matches the sender's display name
      .display_text == sender.display_name
  )
)

Detection logic

Scope: inbound message.

Detects inbound messages claiming to share files or invite access, containing SharePoint or OneDrive links from external domains. The rule identifies suspicious sharing notifications where link display text matches the sender's name rather than a legitimate document name, indicating potential impersonation of legitimate file sharing services.

  1. inbound message
  2. subject.subject matches any of 2 patterns
    • *shared*
    • *invit*
  3. body.current_thread.text matches any of 3 patterns
    • *shared a file with you*
    • *shared with you*
    • *invited you to access a file*
  4. not:
    • body.current_thread.text matches 'invited you to edit'
  5. any of filter(body.current_thread.links) where:
    • .display_text is sender.display_name

Inspects: body.current_thread.links, body.current_thread.links[].display_text, body.current_thread.links[].href_url.domain.domain, body.current_thread.links[].href_url.domain.root_domain, body.current_thread.links[].href_url.query_params, body.current_thread.text, sender.display_name, subject.subject, type.inbound. Sensors: strings.icontains, strings.ilike. Reference lists: $tenant_domains.

Indicators matched (9)

FieldMatchValue
strings.ilikesubstring*shared*
strings.ilikesubstring*invit*
strings.ilikesubstring*shared a file with you*
strings.ilikesubstring*shared with you*
strings.ilikesubstring*invited you to access a file*
body.current_thread.links[].href_url.domain.root_domainequalssharepoint.com
body.current_thread.links[].href_url.domain.root_domainequals1drv.ms
body.current_thread.links[].href_url.domain.root_domainequalsmimecastprotect.com
strings.icontainssubstring.sharepoint.com

Stages and Predicates

Stage 1: mql_rule

and
  not
    body.current_thread.text eq "invited you to edit"
  or
    body.current_thread.text match "invited you to access a file"
    body.current_thread.text match "shared a file with you"
    body.current_thread.text match "shared with you"
  any(filter(body.current_thread.links))
    filter(body.current_thread.links).display_text cross_field_compare "sender.display_name"
  or
    subject.subject match "invit"
    subject.subject match "shared"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
body.current_thread.texteqinvited you to editexcludes:body.current_thread.text field:"body.current_thread.text" value:"invited you to edit"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • *invited you to access a file*
  • *shared a file with you*
  • *shared with you*
field:"body.current_thread.text" kind:wildcard
subject.subjectwildcard
  • *invit*
  • *shared*
field:"subject.subject" kind:wildcard
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

SharePoint OTP for filename matching org name

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

Detects Microsoft One-Time Passcode (OTP) messages where the shared document’s filename matches the sending organization's name. This typically indicates the recipient has verified their email address and is about to access a SharePoint file. Matching the document name to the sender's org is a pattern observed in multi-stage credential phishing campaigns, where attackers use branded file names to increase credibility and lure users into interacting with malicious content.

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
  • headers
  • headers.hops
  • sender.email
  • type

Rule body

type.inbound
// Microsoft sender
and sender.email.domain.root_domain == "microsoft.com"
// message ID contains the proper format for OTP messeges
and (
  (
    strings.istarts_with(headers.message_id, '<OneTimePasscode-')
    and strings.iends_with(headers.message_id, '@odspnotify>')
  )
  // deal with Google thinking the message ID is "broke"
  or (
    strings.icontains(headers.message_id, 'SMTPIN_ADDED_BROKEN')
    and any(headers.hops,
            any(.fields,
                .name == "X-Google-Original-Message-ID"
                and strings.istarts_with(.value, '<OneTimePasscode-')
                and strings.iends_with(.value, '@odspnotify>')
            )
    )
  )
)
// make sure the body has the phrase we need to get the document name
and strings.icontains(body.current_thread.text,
                      'For security purposes, you must enter the code below to verify your account to access'
)
// extract the filename and org name from the body and see if they are equal
and any(regex.iextract(body.current_thread.text,
                       'For security purposes, you must enter the code below to verify your account to access (?P<doc_name>.*)\. The code will only work for.*This email is generated through (?P<org_name>.*)''s use of Microsoft 365\.'
        ),
        .named_groups["doc_name"] =~ .named_groups["org_name"]
)

Detection logic

Scope: inbound message.

Detects Microsoft One-Time Passcode (OTP) messages where the shared document’s filename matches the sending organization's name. This typically indicates the recipient has verified their email address and is about to access a SharePoint file. Matching the document name to the sender's org is a pattern observed in multi-stage credential phishing campaigns, where attackers use branded file names to increase credibility and lure users into interacting with malicious content.

  1. inbound message
  2. sender.email.domain.root_domain is 'microsoft.com'
  3. any of:
    • all of:
      • headers.message_id starts with '<OneTimePasscode-'
      • headers.message_id ends with '@odspnotify>'
    • all of:
      • headers.message_id contains 'SMTPIN_ADDED_BROKEN'
      • any of headers.hops where:
        • any of .fields where all hold:
          • .name is 'X-Google-Original-Message-ID'
          • .value starts with '<OneTimePasscode-'
          • .value ends with '@odspnotify>'
  4. body.current_thread.text contains 'For security purposes, you must enter the code below to verify your account to access'
  5. any of regex.iextract(body.current_thread.text) where:
    • .named_groups['doc_name'] is .named_groups['org_name']

Inspects: body.current_thread.text, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, headers.message_id, sender.email.domain.root_domain, type.inbound. Sensors: regex.iextract, strings.icontains, strings.iends_with, strings.istarts_with.

Indicators matched (7)

FieldMatchValue
sender.email.domain.root_domainequalsmicrosoft.com
strings.istarts_withprefix<OneTimePasscode-
strings.iends_withsuffix@odspnotify>
strings.icontainssubstringSMTPIN_ADDED_BROKEN
headers.hops[].fields[].nameequalsX-Google-Original-Message-ID
strings.icontainssubstringFor security purposes, you must enter the code below to verify your account to access
regex.iextractregexFor security purposes, you must enter the code below to verify your account to access (?P<doc_name>.*)\. The code will only work for.*This email is generated through (?P<org_name>.*)'s use of Microsoft 365\.

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(headers.hops)
        any(headers.hops.fields)
          and
            headers.hops.fields[].name eq "X-Google-Original-Message-ID"
            headers.hops.fields[].value ends_with "@odspnotify>"
            headers.hops.fields[].value starts_with "<OneTimePasscode-"
      headers.message_id contains "SMTPIN_ADDED_BROKEN"
    and
      headers.message_id ends_with "@odspnotify>"
      headers.message_id starts_with "<OneTimePasscode-"
  any(regex.iextract(body.current_thread.text))
    regex.iextract(body.current_thread.text).named_groups['doc_name'] cross_field_compare "regex.iextract(body.current_thread.text).named_groups['org_name']"
  body.current_thread.text contains "For security purposes, you must enter the code below to verify your account to access"
  sender.email.domain.root_domain eq "microsoft.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.