Detection rules › Sublime MQL

Sublime MQL rules: self

Headers: Self-sender using Microsoft CompAuth bypass with credential theft content

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

Detects messages sent to self or invalid domains containing credential theft content that bypass Microsoft's CompAuth while failing both SPF and DMARC authentication checks.

Threat Classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSpoofing, Evasion

Telemetry Coverage

PlatformRecord / event type
SublimeInbound email message

Message Attributes

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

Rule Body

type.inbound
// self sender
and length(recipients.to) == 1
and length(recipients.cc) == 0
and length(recipients.bcc) == 0
and (
  sender.email.email == recipients.to[0].email.email
  or recipients.to[0].email.domain.valid == false
)
// cred theft
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name == "cred_theft" and .confidence != "low"
)
// microsoft compauth pass, but spf and dmarc fail
and any(headers.hops, any(.fields, strings.icontains(.value, 'compauth=pass')))
and not coalesce(headers.auth_summary.dmarc.pass, false)
and not coalesce(headers.auth_summary.spf.pass, false)

Detection Logic

Scope: inbound message.

Detects messages sent to self or invalid domains containing credential theft content that bypass Microsoft's CompAuth while failing both SPF and DMARC authentication checks.

  1. inbound message
  2. length(recipients.to) == 1
  3. length(recipients.cc) == 0
  4. length(recipients.bcc) == 0
  5. any of:
    • sender.email.email is recipients.to[0].email.email
    • recipients.to[0].email.domain.valid is False
  6. any(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence != "low" )
  7. any of headers.hops where:
    • any of .fields where:
      • .value contains 'compauth=pass'
  8. not:
    • coalesce(headers.auth_summary.dmarc.pass, false)
  9. not:
    • coalesce(headers.auth_summary.spf.pass, false)

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.hops, headers.hops[].fields, headers.hops[].fields[].value, recipients.bcc, recipients.cc, recipients.to, recipients.to[0].email.domain.valid, recipients.to[0].email.email, sender.email.email, type.inbound. Sensors: ml.nlu_classifier, strings.icontains.

Indicators Matched (2)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
strings.icontainssubstringcompauth=pass

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
  not
    and
      headers.auth_summary.spf.pass eq "true"
      headers.auth_summary.spf.pass is_not_null
  any(headers.hops)
    any(headers.hops.fields)
      headers.hops.fields.value contains "compauth=pass"
  or
    recipients.to[0].email.domain.valid eq "false"
    sender.email.email cross_field_compare "recipients.to[0].email.email"
  recipients.bcc length_compare "0"
  recipients.cc length_compare "0"
  recipients.to length_compare "1"
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n        .name == \"cred_theft\" and .confidence != \"low\"\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
recipients.to[0].email.domain.valideq
  • false transforms: boolean corpus 10 (mql 10)
field:"recipients.to[0].email.domain.valid" kind:eq value:"false"
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
headers.auth_summary.spf.passeqtrueexcludes:headers.auth_summary.spf.pass field:"headers.auth_summary.spf.pass" value:"true"
headers.auth_summary.spf.passis_not_null(no value, null check)excludes:headers.auth_summary.spf.pass

Link: Single character path with credential theft body and self sender behavior or invalid recipient

#

Self-sender with copy/paste instructions and suspicious domains (French/Français)

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

Detects messages where the sender emails themselves with French text containing 'copier' (copy) and 'coller' (paste) instructions, along with suspicious domains like pages.dev or web.app. The subject line contains both the sender's email and display name, which are different values.

Threat Classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, Free subdomain host, Social engineering

Telemetry Coverage

PlatformRecord / event type
SublimeInbound email message

Message Attributes

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

Rule Body

type.inbound
// self sender
and (
  length(recipients.to) == 1
  and length(recipients.cc) == 0
  and sender.email.email in map(recipients.to, .email.email)
)
and strings.icontains(subject.subject, sender.email.email)
and strings.icontains(subject.subject, sender.display_name)
and sender.email.email != sender.display_name
// copy
and strings.icontains(body.current_thread.text, 'copier')
// paste
and strings.icontains(body.current_thread.text, 'coller')
and (
  strings.contains(body.current_thread.text, '.pages.dev')
  or strings.contains(body.current_thread.text, '.web.app')
)

Detection Logic

Scope: inbound message.

Detects messages where the sender emails themselves with French text containing 'copier' (copy) and 'coller' (paste) instructions, along with suspicious domains like pages.dev or web.app. The subject line contains both the sender's email and display name, which are different values.

  1. inbound message
  2. all of:
    • length(recipients.to) == 1
    • length(recipients.cc) == 0
    • sender.email.email in map(recipients.to, .email.email)
  3. strings.icontains(subject.subject, sender.email.email)
  4. strings.icontains(subject.subject, sender.display_name)
  5. sender.email.email is not sender.display_name
  6. body.current_thread.text contains 'copier'
  7. body.current_thread.text contains 'coller'
  8. any of:
    • body.current_thread.text contains '.pages.dev'
    • body.current_thread.text contains '.web.app'

Inspects: body.current_thread.text, recipients.cc, recipients.to, recipients.to[].email.email, sender.display_name, sender.email.email, subject.subject, type.inbound. Sensors: strings.contains, strings.icontains.

Indicators Matched (4)

FieldMatchValue
strings.icontainssubstringcopier
strings.icontainssubstringcoller
strings.containssubstring.pages.dev
strings.containssubstring.web.app

Stages and Predicates

Stage 1: mql_rule

and
  or
    body.current_thread.text contains ".pages.dev"
    body.current_thread.text contains ".web.app"
  body.current_thread.text contains "coller"
  body.current_thread.text contains "copier"
  recipients.cc length_compare "0"
  recipients.to length_compare "1"
  sender.email.email cross_field_compare "sender.display_name"
  sender.email.email macro "sender.email.email in map(recipients.to, .email.email)"
  strings.icontains func_call "strings.icontains(subject.subject, sender.display_name)"
  strings.icontains func_call "strings.icontains(subject.subject, sender.email.email)"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textcontains
  • .pages.dev
  • .web.app
  • coller
  • copier
field:"body.current_thread.text" kind:contains
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Back to all Sublime MQL rules