• Sublime Core Feed
High Severity

Brand impersonation: DocuSign

Labels

Credential Phishing
Impersonation: Brand
Lookalike domain
Social engineering
Spoofing
Header analysis
Sender analysis
URL analysis

Description

Attack impersonating a DocuSign request for signature.

References

Sublime Security
Created Aug 17th, 2023 • Last updated May 21st, 2025
Feed Source
Sublime Core Feed
Source
GitHub
type.inbound
and (
  // orgs can have docusign.company.com
  strings.ilike(sender.email.email, '*docusign.net*', '*docusign.com*')

  // if the above is true, you'll see a "via Docusign"
  or strings.ilike(sender.display_name, '*docusign*')

  // detects 1 character variations,
  // such as DocuSlgn (with an "L" instead of an "I")
  or strings.ilevenshtein(sender.display_name, "docusign") == 1
  or strings.ilike(sender.display_name, "*docuonline*", "*via *signature*")
  or (
    strings.istarts_with(body.html.inner_text, "docusign")
    and not strings.istarts_with(body.current_thread.text, "docusign")
  )
  // docusign is found in current thread AND contains docusign wording within current_thread or subject
  or (
    regex.icontains(body.current_thread.text, '\bdocu.?sign\b')
    and (
      // additional context from body.current_thread.text
      strings.istarts_with(body.current_thread.text, "DOCUSIGN\n", )
      or regex.icontains(body.current_thread.text,
                         'You have received a ([^\s]+\s)?document',
      )
      or strings.icontains(body.current_thread.text,
                           'a document to review and sign',
      )
      or strings.icontains(body.current_thread.text,
                           'A document is available for you',
      )
      or strings.icontains(body.current_thread.text,
                           'a document ready for you',
      )
      or strings.icontains(body.current_thread.text,
                           'This email contains a secure link to DocuSign'
      )
      or strings.icontains(body.current_thread.text,
                           'All parties have completed with Docusign'
      )
      or strings.icontains(body.current_thread.text,
                           'the signing of this document has been completed'
      )
      or strings.icontains(body.current_thread.text,
                           'Please use the link above to Docusign'
      )
      or strings.icontains(body.current_thread.text, 'Review on Docusign')
      or strings.icontains(body.current_thread.text, 'Completed with Docusign')
      or strings.icontains(body.current_thread.text, 'Completed on Docusign')
      or strings.icontains(body.current_thread.text, 'Complete with Docusign')
      or strings.icontains(body.current_thread.text,
                           'please review and complete with DocuSign'
      )
      or strings.icontains(body.current_thread.text,
                           'We appreciate you choosing DocuSign'
      )
      or strings.icontains(body.current_thread.text,
                           'A document has been sent to you for'
      )
      or strings.icontains(body.current_thread.text, 'Please Sign docusign')
      or strings.icontains(body.current_thread.text, 'This email was sent via DocuSign')
      or strings.icontains(body.current_thread.text, 'This email was sent to you via DocuSign')
      or strings.icontains(body.current_thread.text, 'This message was sent via DocuSign')
      or strings.icontains(body.current_thread.text, 'This message was sent to you via DocuSign')
      or strings.icontains(body.current_thread.text, 'review via DocuSign Electronic Signature')
      or strings.icontains(body.current_thread.text, 'sent to you by DocuSign')
      or strings.icontains(body.current_thread.text, 'Processed by DocuSign')
      or strings.icontains(body.current_thread.text,
                           'Please read and sign the document'
      )
      or strings.icontains(body.current_thread.text,
                           'Please kindly review and sign the '
      )
      or strings.icontains(body.current_thread.text,
                           'Your document is pending review and signature'
      )
      or strings.icontains(body.current_thread.text,
                           'pending document for your signature'
      )
      or strings.icontains(body.current_thread.text,
                           'your review and signature'
      )
      or strings.icontains(body.current_thread.text, 'a pending document for')
      or strings.icontains(body.current_thread.text, 'Your document is ready')
      or strings.icontains(body.current_thread.text,
                           'This email is automatically generated by DocuSign'
      )
      or strings.icontains(body.current_thread.text,
                           'Your document has been completed'
      )
      // docusign is "near" review and sign or sign and return
      or regex.icontains(body.current_thread.text,
                         'Review\s*(?:and\s*|&\s*)Sign.{0,40}docusign',
                         'docusign.{0,40}Review\s*(?:and\s*|&\s*)Sign',
                         'Sign\s*(?:and\s*|&\s*)Return.{0,40}docusign',
                         'Sign\s*(?:and\s*|&\s*)Return.docusign.{0,40}'
      )

      // additional context from subject.subject
      or strings.icontains(subject.subject, 'complete with docusign')
      or strings.icontains(subject.subject, 'signature request')
      or regex.icontains(subject.subject, 'Review\s*(?:and\s*|&\s*)Sign')
      or regex.icontains(subject.subject, 'Sign\s*(?:and\s*|&\s*)Return')
      or strings.icontains(subject.subject, 'Please Docusign')
      or strings.icontains(subject.subject, 'Docusign has sent')
    )
  )
  or (
    // negate replies/forwards which involve a legit docusign message-id format
    not any(headers.references,
            strings.iends_with(., 'docusign.net')
            and regex.imatch(., '[0-9a-f]{32}@(?:[^\.]+\.)?docusign.net')
    )
    and (
      (
        sender.display_name is not null
        and regex.icontains(sender.display_name, '\bdocu\b')
        and strings.icontains(sender.display_name, 'sign')
      )
      or (
        subject.subject is not null
        and regex.icontains(subject.subject, '\bdocu\b')
        and strings.icontains(subject.subject, 'sign')
      )
      or (
        (
          regex.icontains(body.html.raw,
                          'Powered by.{0,6}(?:\s*<\/?[^\>]+\>\s*)+<img[^\>]+(?:src="https:\/\/docucdn-a\.akamaihd\.net\/[^\"]+email-logo.png"|alt="DocuSign")'
          )
          or regex.icontains(body.current_thread.text, 'Powered by\s*DocuSign')
        )
        // limit it to where the powered by is within the current thread
        and strings.icontains(body.current_thread.text, 'Powered by')
      )
      // footer disclaimers
      or strings.icontains(body.current_thread.text,
                           'using the Docusign Electronic Signature Service'
      )
      or strings.icontains(body.current_thread.text,
                           'who uses the DocuSign Electronic Signature Service'
      )
      or strings.icontains(body.current_thread.text,
                           'Thank you for choosing DocuSign'
      )
      or (
        (
          strings.icontains(body.current_thread.text,
                            'Alternate Signing Method'
          )
          or strings.icontains(body.current_thread.text, 'Alternative Access')
        )
        and regex.icontains(body.current_thread.text,
                            '(?:Click|Select) ''Access Documents'', and enter '
        )
      )
      or (
        strings.icontains(body.current_thread.text,
                          'Please do not share this email, link, or access code with others'
        )
        and not sender.email.domain.root_domain in (
          "insuresign.com",
          "clixsign.com",
          "esignlive.com",
          "clickcontracts.com",
          "sadq.sa",
          "vasion.com",
          "chubb.com", // insurance company
        )
      )
      or (
        strings.icontains(body.current_thread.text, 'Docusign provides a ')
        and strings.icontains(body.current_thread.text,
                              'solution for Digital Transaction Management'
        )
      )
      or strings.icontains(body.current_thread.text,
                           'a secure link to DocuSign'
      )

      // footer links
      or (
        length(filter(body.links,
                      (
                        .href_url.domain.domain == "support.docusign.com"
                        and strings.contains(.href_url.path, '/articles/')
                      )
                      or .href_url.domain.domain == "community.docusign.com"
                      or .href_url.domain.domain == "protect.docusign.com"
                      or .href_url.domain.domain == "app.esign.docusign.com"
               )
        ) >= 2
        // and the display_text for these links are within the current thread
        and (
          strings.icontains(body.current_thread.text, 'Declining to sign')
          or strings.icontains(body.current_thread.text,
                               'Managing notifications'
          )
          or strings.icontains(body.current_thread.text,
                               'How to Sign a Document'
          )
          or strings.icontains(body.current_thread.text,
                               'Docusign Support Center'
          )
          or strings.icontains(body.current_thread.text, 'Report this email')
          or strings.icontains(body.current_thread.text, 'Docusign Community')
          or strings.icontains(body.current_thread.text,
                               'Connect with our support team'
          )
          or strings.icontains(body.current_thread.text, 'Unsubscribe')
          or strings.icontains(body.current_thread.text, 'Manage Preferences')
        )
      )
    )
  )
  or (
    (
      regex.icontains(body.html.raw,
                      '<font size="?[0-9]"?[^\>]*>DocuSign</font>'
      )
      or regex.icontains(body.html.raw, '\nDocu(?:<[^\>]+>\s*)+Sign<')
      or regex.icontains(body.html.raw,
                         '<span[^>]*style="[^"]*">Docu.?Sign<\/span>'
      )

      or any(html.xpath(body.html, '//h1').nodes,
             regex.icontains(.display_text, 'Docu.?Sign')
      )
      or regex.icontains(body.html.raw,
                         '<span[^>]*style="[^"]*">(Docu|D(?:ocu?)?)<\/span>(?:<[^\>]+\>){0,2}<span[^>]*style="[^"]*">(Sign|S(?:ign?)?)<\/span>'
      )
      // any bold text contains docusign
      or any(html.xpath(body.html, '//strong').nodes,
             regex.imatch(.display_text, 'Docu.?Sign')
      )
      // title starts with Docusign
      or any(html.xpath(body.html, '//title').nodes,
             regex.icontains(.display_text, '^docu.?sign')
      )
      // a div with a class of logo contains the display text of docusign
      or any(html.xpath(body.html, '//div[@class="logo"]').nodes,
             strings.icontains(.display_text, 'Docusign')
      )
      // image contains an alt text of docusign
      or any(html.xpath(body.html, '//img/@alt').nodes, .raw =~ "docusign")

      // Basic variations with HTML encoding
      // use of regex extract allows 
      or any(regex.iextract(body.html.raw,
                            '(?:D|&#68;|&#x44;)(?:&#?[0-9a-fA-F]{2,6};|\s|o|о|&#1086;|&#x43e;)(?:&#?[0-9a-fA-F]{2,6};|\s|c|с|&#1089;|&#x441;)u(?:&#?[0-9a-fA-F]{2,6};|\s)?S(?:&#?[0-9a-fA-F]{2,6};|\s|i|і|&#1110;|&#x456;)(?:&#?[0-9a-fA-F]{2,6};|\s|g|ɡ|&#609;|&#x261;)(?:n|&#110;|&#x6e;)'
             ),
             .full_match !~ "docusign"
      )
      //  Common homograph patterns
      or any(regex.iextract(body.html.raw,
                            '(?:[DⅮᎠᗞᗡ𝐃𝐷𝑫𝒟𝓓𝔇𝔻𝕯𝖣])\s*(?:[oοоօ0Ооʘ◯])\s*(?:[cсçҫ¢ϲС])\s*u\s*(?:[sѕЅ5$])\s*(?:[iіІ1l!|])\s*(?:[gǵġģ9ɡ])\s*(?:[nոռℼη𝐧𝑛𝒏𝓃𝓷𝔫𝕟𝖓])'
             ),
             .full_match !~ "docusign"
      )

      // Look for HTML entities for each letter in sequence
      or any(regex.iextract(body.html.raw,
                            '(?:D|&#68;|&#x44;)(?:o|о|&#111;|&#x6f;|&#1086;|&#x43e;|&#959;|&#x3bf;)(?:c|с|&#99;|&#x63;|&#1089;|&#x441;|&#1010;|&#231;|&#x67;|&#265;|&#x109;)(?:u|&#117;|&#x75;|&#1091;|&#x443;|&#965;|&#x3c5;)(?:s|&#115;|&#x73;|&#1109;|&#x455;)(?:i|і|&#105;|&#x69;|&#1110;|&#x456;|&#305;|&#x131;)(?:g|&#103;|&#x67;|&#609;|&#x261;|&#287;|&#x11f;)(?:n|&#110;|&#x6e;|&#1085;|&#x43d;|&#951;|&#x3b7;)'
             ),
             .full_match !~ "docusign"
      )

      // Handle repeated HTML entities and variation selectors (using Unicode class)                           
      or any(regex.iextract(body.html.raw,
                            'D(?:&#[0-9]{1,7};)*\p{Mn}*o(?:&#[0-9]{1,7};)*\p{Mn}*c(?:&#[0-9]{1,7};)*\p{Mn}*u(?:&#[0-9]{1,7};)*\p{Mn}*[Ss](?:&#[0-9]{1,7};)*\p{Mn}*i(?:&#[0-9]{1,7};)*\p{Mn}*g(?:&#[0-9]{1,7};)*\p{Mn}*n'
             ),
             .full_match !~ "docusign"
      )
    )
    and (
      regex.icontains(body.html.raw,
                      'b(?:ackground(?:-color)?|g?color):\s*rgb\(30,\s*76,\s*161\)',
                      'b(?:ackground(?:-color)?|g?color):\s*rgb\(61,\s*170,\s*73\)'
      )
      or regex.icontains(body.html.raw,
                         '<(?:div|td|table)[^>]*b(?:ackground(?:-color)?|g?color)(?::|=)\s*\"?#1e4ca1[^>]*>',
      )
      or regex.icontains(body.html.raw,
                         'b(?:ackground(?:-color)?|g?color)(?::|=)\s*\"?#(?:214e9f|3260a7|0056b3|1e4ca1|214395|325bb8|3c60ad)'
      )
    )
  )
)

// identifies the main CTA in the email, eg "Review now" or "Review document"
// this should always be a known docusign domain,
// even with branded docusign subdomains
and (
  any(
      // filter links that match docusign wording
      filter(body.links,
             // we've observed invisible characters in the display name
             // such as U+034f(look carefully): "Revi͏ew Now"
             (
               strings.ilevenshtein(.display_text, "Review Now") <= 3
               or strings.ilevenshtein(.display_text, "Review and Sign") <= 3
               or (
                 strings.icontains(.display_text, "Review")
                 // negate benign uses of the "review" term
                 and not (
                   strings.icontains(.display_text, "Review Us")
                   or strings.icontains(.display_text, "leave us a review")
                   or regex.icontains(.display_text, '\bReviews\b')
                   // don't match microsoft quarantine messages
                   or (
                     strings.icontains(.display_text, "Review Message")
                     and (
                       .href_url.domain.domain == "security.microsoft.com"
                       and .href_url.path == "/quarantine"
                     )
                   )

                 )
               )
               or strings.icontains(.display_text, "document")
               or strings.icontains(.display_text, "docusign")
               or strings.icontains(.display_text, "Review on Docusign")
               or (
                 strings.icontains(.display_text, "Sign")
                 and strings.icontains(.display_text, "Now")
               )
             )
      ),
      // ensure those links aren't legit
      not .href_url.domain.root_domain in (
        "docusign.com",
        "docusign.net",
        'docusign.co.uk',
        'docusign.com.br',
        'docusign.fr',
        // other e-signature companies which use simliar wording
        "insuresign.com",
        "clixsign.com",
        "esignlive.com",
        "clickcontracts.com",
        "adobesign.com",
        "hellosign.com",
      )
      and not (
        .href_url.domain.root_domain == "mimecastprotect.com"
        and (
          .href_url.query_params is not null
          and regex.icontains(.href_url.query_params,
                              'domain=(?:\w+\.)?docusign.(?:net|com|co\.uk|com\.br|fr)',
                              // other e-signature companies
                              'domain=(?:\w+\.)?(?:insuresign\.com|clixsign\.com|esignlive\.com|clickcontracts\.com|adobesign\.com|hellosign\.com)'
          )
        )
      )
  )
  // Suspicious attachment
  or any(attachments,
         (
           .file_extension in~ ("html", "htm", "shtml", "dhtml")
           or .file_extension in~ $file_extensions_common_archives
           or .file_type == "html"
           or .content_type == "text/html"
         )
         and 1 of (
           (
             regex.icontains(file.parse_html(.).raw, '\s{0,}<script.*')
             and regex.icontains(file.parse_html(.).raw, "</script>")
           ),
           strings.ilike(file.parse_html(.).raw,
                         "*createElement*",
                         "*appendChild*",
                         "*createObjectURL*"
           ),
           strings.icount(file.parse_html(.).raw, "/*") > 10,
           any($free_subdomain_hosts, strings.icontains(..file_name, .))
         )
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  coalesce(sender.email.domain.root_domain in $high_trust_sender_root_domains
           and not headers.auth_summary.dmarc.pass,
           false
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
// negation for messages traversing docusign.net
// happens with custom sender domains
and not (
  any(headers.domains, .root_domain == "docusign.net")
  and headers.auth_summary.spf.pass
  and headers.auth_summary.dmarc.pass
)

// adding negation for messages originating from docusigns api
// and the sender.display.name contains "via"
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")
)
MQL Rule Console
DocsLearning Labs

Playground

Test against your own EMLs or sample data.

Share

Post about this on your socials.

Get Started. Today.

Managed or self-managed. No MX changes.

Get Started