Suspicious invoice reference with missing or image-only attachments

This rule flags emails that reference invoices or payments but have suspicious characteristics: attachments are either missing or only images. It also checks for misleading links disguised as attachments and the presence of invoice-related keywords. The rule looks for potential credential theft or unusual requests, making it a strong indicator of phishing attempts.

Sublime rule (View on GitHub)

  1name: "Suspicious invoice reference with missing or image-only attachments"
  2description: "This rule flags emails that reference invoices or payments but have suspicious characteristics: attachments are either missing or only images. It also checks for misleading links disguised as attachments and the presence of invoice-related keywords. The rule looks for potential credential theft or unusual requests, making it a strong indicator of phishing attempts."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  
  8  // more than 0 but less than 20 links
  9  and 0 < length(body.links) < 20
 10  
 11  // all attachments are images or there are 0 attachments
 12  and (
 13    length(attachments) > 0 and all(attachments, .file_type in $file_types_images)
 14    or length(attachments) == 0
 15  )
 16  
 17  // subject contains payment/invoice language
 18  and (
 19    any(ml.nlu_classifier(subject.subject).tags, .name in ("payment", "invoice"))
 20    or regex.contains(subject.subject,
 21                      '(?:\binv(?:oice|o)\b|in_v|in-voice|pay(?:ment|mnt)|pymt|\brec(?:eipt|pt|iept)\b|rcpt|confirm(?:ation)|cnfrm|cnf|po\b|p\.o\.|purch(?:ase)?-?order|\bord(?:er)?\b|bill(?:ing)|billing-info|transact(?:ion)|txn|trx|\bstmt\b|\bstmnt\b|remit(?:tance)|rmt|remndr|remind|\bdue(?:-date)\b|ovrdue|overdue|\bbal(?:ance)\b|\bpaid(?:-invoice)\b|requires\s+your\s+a(?:ttention|ction)|\b[fF]inal\s+(?:[nN]otice|[uU]npaid).{0,20}[iI]nvoice)',
 22                      // suspicious invoice format
 23                      '\d{6}\b.{10,30}(\d{2}\.){3}pdf'
 24    )
 25  )
 26  
 27  // link display text ends in a file extension or contain common payment terms
 28  and (
 29    any(body.links,
 30        regex.imatch(.display_text,
 31                     '.*\.(?:doc|docm|docx|dot|dotm|pdf|ppa|ppam|ppsm|ppt|pptm|pptx|wbk|xla|xlam|xlm|xls|xlsb|xlsm|xlsx|xlt|xltm)$'
 32        )
 33    )
 34    or any(body.links,
 35           regex.icontains(.display_text,
 36                           '(?:\binv(?:oice|o)\b|in_v|in-voice|pay(?:ment|mnt)|pymt|\brec(?:eipt|pt|iept)\b|rcpt|req(?:uest)|rqst|\brq\b|\bpo\b|p\.o\.|purch(?:ase)?-?order|\bord(?:er)?\b|bill(?:ing)|billing-info|transact(?:ion)|txn|trx|\bstmt\b|\bstmnt\b|remit(?:tance)|rmt|remndr|remind|\bdue(?:-date)\b|ovrdue|overdue|\bbal(?:ance)\b|\bpaid(?:-invoice)\b|completed\s+doc(?:s|ument|uments)?\b)'
 37           )
 38    )
 39    or (
 40      any(body.links,
 41          regex.icontains(.display_text, '\bview\s+(invoice|attachment)')
 42      )
 43      and any([body.plain.raw, body.html.inner_text],
 44              any(ml.nlu_classifier(.).intents,
 45                  .name == "cred_theft" and .confidence == "high"
 46              )
 47      )
 48    )
 49  )
 50  
 51  // the body references an attachment 
 52  and (
 53    strings.contains(body.current_thread.text, "attach")
 54    // negate warning banners warning about the attachment(s)
 55    and (
 56      not (
 57        (
 58          regex.count(body.current_thread.text, "attach") == 1
 59          and regex.icontains(body.current_thread.text,
 60                              "(caution|warning).{0,30}attach"
 61          )
 62        )
 63        or ( // WeTransfer expiry warning notification
 64          sender.email.email == "noreply@wetransfer.com"
 65          and any(body.links,
 66                  .display_text == "Don't send me these expiry reminders anymore"
 67          )
 68        )
 69      )
 70    )
 71  )
 72  
 73  // body text is determined to contain cred_theft language by nlu or contains a request with suspicious keywords
 74  and (
 75    not (
 76      any(ml.nlu_classifier(body.current_thread.text).topics,
 77          .name in ("Shipping and Package", "Order Confirmations")
 78          and .confidence == "high"
 79      )
 80    )
 81    and (
 82      any(ml.nlu_classifier(body.current_thread.text).intents,
 83          .name == "cred_theft"
 84      )
 85      or any(ml.nlu_classifier(body.current_thread.text).entities,
 86             .name == "request"
 87             and (
 88               strings.icontains(.text, "kindly")
 89             )
 90      )
 91    )
 92  )
 93  // negate highly trusted sender domains unless they fail DMARC authentication
 94  and (
 95    (
 96      sender.email.domain.root_domain in $high_trust_sender_root_domains
 97      and not headers.auth_summary.dmarc.pass
 98    )
 99    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
100  )
101  and not profile.by_sender().solicited  
102
103attack_types:
104  - "Credential Phishing"
105tactics_and_techniques:
106  - "Social engineering"
107detection_methods:
108  - "Content analysis"
109  - "Computer Vision"
110  - "File analysis"
111  - "Natural Language Understanding"
112  - "Sender analysis"
113id: "466c1680-b9ff-5bd0-baf8-e65cca99d18b"
to-top