PDF Libraries: From Desktop to Browser

▶ Watch (0:09)

PDF is a 30-year-old format created by Adobe in 1993. Adobe added JavaScript support in 1999 to automate form validation in tax and government documents. The shift from desktop readers to browser-based processing began in 2010 when Chrome introduced native PDF rendering. Mozilla released PDF.js in 2011, a PDF reader written entirely in JavaScript. Apryse (formerly PDFTron) released its web viewer SDK in 2012. Apryse powers Dropbox, Smallpdf, and Lumin PDF. PDF.js is downloaded over 3.5 million times per week from npm.

Two CVEs in PDF.js: Same Root Cause, Six Years Apart

▶ Watch (7:22)

CVE-2018-5158 was the first cross-site scripting vulnerability in PDF.js, reported by Vladimir Palant. The postscript calculator function did not sanitize user input. The library checked if the input was an array but did not validate each item inside it. CVE-2024-4367 appeared six years later, reported by Thomas Rinsma. The font matrix input was another array that was not properly sanitized. Both vulnerabilities allowed JavaScript injection through a malicious PDF. PDF.js has only two known CVEs, making it a solid library despite the recurring pattern.

Apryse Sandbox Bypass: JavaScript Sandboxed in JavaScript

▶ Watch (19:11)

Apryse SDK supports Adobe’s JavaScript API for PDF forms. It implements a sandbox by defining a long blocklist of browser APIs as undefined. Gubello bypassed this by using the delete operator on the undefined variables, restoring the browser’s default API. His payload used console.println, an Adobe-specific API mapped to console.log. The sandbox ran the injected code via eval. Apryse’s approach contrasts with PDF.js, which sandboxes JavaScript inside WebAssembly. Wasm prevents access to the DOM even if the sandbox is bypassed.

Dropbox Mitigation: Layers That Made Exploitation Impossible

▶ Watch (33:14)

Gubello found a third vulnerability in Apryse SDK that did not use eval. A form annotation’s default value was rendered via innerHTML without sanitization. This bypassed Dropbox’s Content Security Policy because the CSP allowed unsafe-inline. However, Dropbox ran the PDF viewer on an isolated subdomain with no user session data. Communication with the main application used postMessage. Gubello could execute JavaScript inside the official Dropbox PDF viewer but could not access the DOM or cookies. The layered defense made the vulnerability unexploitable.

PDF.js in Electron: From XSS to Remote Code Execution

▶ Watch (36:51)

Electron applications like Logseq use PDF.js to render PDFs natively. A researcher found that Slack used an outdated PDF.js version, enabling XSS. Gubello demonstrated a similar attack on Logseq. A malicious PDF opened in Logseq triggered a cross-site scripting vulnerability in PDF.js. The injected JavaScript then called Logseq’s internal API to execute shell commands via git. The demo opened a calculator on the host system. The PDF file served as the initial vector, and the electron app’s API surface enabled privilege escalation.

Notable Quotes

“You cannot be the sandbox in pure JavaScript because you can always find a way to bypass it.” Luigi Gubello · ▶ Watch (22:11)

“If you define a variable as undefined but then I delete it the browser just switch to the default one.” Luigi Gubello · ▶ Watch (26:06)

“Even if I found a cross scripting even if I was able to run JavaScript inside the official Dropbox PDF viewer I was not able to exploit it because I haven’t access to the Doom.” Luigi Gubello · ▶ Watch (36:35)

“This means that a proof of concept in a cross script based on PDF cannot be just app.alert one.” Luigi Gubello · ▶ Watch (43:48)

Key Takeaways

  • PDF.js has only two CVEs, both from unsanitized array inputs six years apart.
  • JavaScript sandboxes written in JavaScript can be bypassed with the delete operator.
  • WebAssembly sandboxing prevents DOM access even if the sandbox is broken.
  • Dropbox’s layered defenses made an exploitable XSS unexploitable.
  • A PDF XSS in an Electron app can escalate to remote code execution.

About the Speaker(s)

Luigi Gubello is a Security Engineer at Neko Health. He sometimes tries to hack stuff. He has been investigated by the authorities due to an SQL injection, financed by the powers that be, someone said.