• Sublime Core Feed
High Severity

Attachment: Suspicious PDF Created With Headless Browser

Labels

Credential Phishing
Evasion
PDF
Content analysis
Exif analysis
File analysis
Optical Character Recognition

Description

Detects PDF documents containing a table of contents that were generated using HeadlessChrome, Chromium with Skia/PDF, or QT with empty metadata fields - common characteristics of automated malicious document creation.

References

No references.

Sublime Security
Created May 28th, 2025 • Last updated Jun 30th, 2025
Feed Source
Sublime Core Feed
Source
GitHub
type.inbound
and (
  // directly attached PDF
  any(filter(attachments, .file_type == "pdf"),
      any(file.explode(.), strings.contains(.scan.ocr.raw, 'TABLE OF CONTEN'))
      // the Table of contents can be on another page
      and any(file.explode(.),
            regex.icontains(.scan.ocr.raw,
                            '(?:[\r\n]|^)+(?:\s*1\s*(?:\.|:))?\s*Introduction'
            )
            or strings.icontains(.scan.ocr.raw,
                            'marked in red'
            )
      )
      and (
        (
          (
            strings.icontains(beta.parse_exif(.).creator, 'HeadlessChrome')
            or strings.icontains(beta.parse_exif(.).creator, 'Chromium')
          )
          and strings.icontains(beta.parse_exif(.).producer, 'Skia/PDF')
        )
        or (
          any(beta.parse_exif(.).fields,
              .key == "Creator"
              and (.value == "" or strings.istarts_with(.value, 'wkhtmltopdf'))
          )
          and any(beta.parse_exif(.).fields,
                  .key == "Title"
                  and (.value == "" or .value in ('Company HandBook'))
          )
          and strings.istarts_with(beta.parse_exif(.).producer, 'QT ')
        )
      )
  )
  // or within an attached EML
  or any(filter(attachments,
                .content_type == "message/rfc822" or .file_extension == "eml"
         ),
         any(filter(file.parse_eml(.).attachments, .file_type == "pdf"),
             any(file.explode(.),
                 strings.contains(.scan.ocr.raw, 'TABLE OF CONTEN')
             )
             // the Table of contents can be on another page
             and any(file.explode(.),
                     regex.icontains(.scan.ocr.raw,
                                     '(?:[\r\n]|^)+1\s*(\.|:)\s*Introduction'
                     )
             )
             and (
               (
                 (
                   strings.icontains(beta.parse_exif(.).creator,
                                     'HeadlessChrome'
                   )
                   or strings.icontains(beta.parse_exif(.).creator, 'Chromium')
                 )
                 and strings.icontains(beta.parse_exif(.).producer, 'Skia/PDF')
               )
               or (
                 any(beta.parse_exif(.).fields,
                     .key == "Creator"
                     and (
                       .value == ""
                       or strings.istarts_with(.value, 'wkhtmltopdf')
                     )
                 )
                 and any(beta.parse_exif(.).fields,
                         .key == "Title"
                         and (.value == "" or .value in ('Company HandBook'))
                 )
                 and strings.istarts_with(beta.parse_exif(.).producer, 'QT ')
               )
             )
         )
  )
)
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