Aug 7, 2026·5 min read·0 visits
A high-severity Cross-Site Scripting (XSS) vulnerability exists in ngx-extended-pdf-viewer. By parsing a crafted PDF with XML Forms Architecture (XFA) elements, attackers can bypass sanitizers and execute arbitrary script inside the application context.
The ngx-extended-pdf-viewer library embeds a version of Mozilla's pdf.js that contains vulnerability CVE-2026-16633. This vulnerability allows arbitrary JavaScript execution (XSS) upon rendering a malicious PDF file.
The ngx-extended-pdf-viewer library embeds a customized, direct-bundled version of Mozilla's pdf.js rendering engine instead of relying on standard external package dependency models. This integration model limits vulnerability detection from automated software composition analysis (SCA) tools, introducing risks associated with hidden dependencies (CWE-1103).
Under default configurations, the application enables XML Forms Architecture (XFA) parsing. This default setting exposes a significant attack surface to malicious actors. When a victim opens a specially crafted PDF document, the engine processes malicious parameters in XFA templates without proper sanitization, leading to client-side code execution.
The vulnerability is tracked under GitHub Security Advisory GHSA-W9HM-4M3M-FXMM, mapping upstream to CVE-2026-16633. It permits unauthenticated remote code execution on the client-side, translating directly to Cross-Site Scripting (XSS) in the context of the hosting web application's origin.
The root cause of this vulnerability lies in the serialization and encoding logic within two core utility functions in pdf.js: escapePDFName and encodeToXmlString.
The first failure is in the character encoding logic of escapePDFName. When encoding PDF Name objects containing control characters (character codes below 0x10), the system does not zero-pad the resulting hexadecimal notation. This results in characters such as \x05 escaping to #5 instead of #05. An attacker can align syntax-active characters directly following a control character, such as appending c to \x05 to yield #5c. When decoded, this sequence evaluates to \ (backslash), allowing the attacker to escape string literal boundaries within dynamically generated scripts.
The second failure occurs within the encodeToXmlString function, which handles serialization for XML/HTML nodes in XFA forms. The logic incorrectly identifies single-unit Basic Multilingual Plane (BMP) non-characters (such as U+FFFE and U+FFFF) as surrogate pairs. When processing these units, the parser increments its loop index artificially, skipping and dropping the next character in the sequence. By strategically inserting non-characters, attackers can drop sanitization filters, allowing raw script tags and active elements to pass into the rendering boundary.
The code comparison highlights the parsing flaws and the exact remediations applied in the upstream repository.
In the vulnerable version of escapePDFName, the hex serialization lacks padding:
// Vulnerable code in core_utils.js
function escapePDFName(str) {
return str.replace(/[\x00-\x1f]/g, (char) => {
// Bug: No zero-padding for character codes lower than 16
return "#" + char.charCodeAt(0).toString(16);
});
}The patch introduces standard zero-padding to secure character alignment:
// Patched code in core_utils.js
function escapePDFName(str) {
return str.replace(/[\x00-\x1f]/g, (char) => {
// Correct: Zero-pads the hex representation to exactly 2 digits
return "#" + char.charCodeAt(0).toString(16).padStart(2, "0");
});
}Additionally, the parsing logic in encodeToXmlString mistakenly handled single-unit non-characters as multi-unit surrogate pairs:
// Vulnerable loop check in core_utils.js
if (char > 0xd7ff && (char < 0xe000 || char > 0xfffd)) {
// Bug: Incorrect index incrementation on single non-characters
i++;
}The fix establishes verified evaluation of high/low surrogate pairs before skipping indexes:
// Patched logic in core_utils.js
const next = str.charCodeAt(i + 1);
if (char >= 0xd800 && char <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {
// Correct: Only skips index if a valid low surrogate matches the current high surrogate
i++;
}To execute this attack, an offensive actor must first construct a PDF template containing custom XFA structures with malicious name properties or XML definitions. This payload integrates the character truncation and alignment sequences to bypass HTML validators.
The document is then delivered to a target user who views it inside an application using a vulnerable ngx-extended-pdf-viewer build. Because the viewer has XFA enabled by default, it automatically invokes the parser on the malformed elements.
As the client processes the form templates, the parser reconstructs the corrupted XML sequences into functional markup tags. The payload escapes the script string literal context and runs client-side JavaScript on the hosting platform's domain, granting the attacker unauthenticated execution capability.
The impact of this vulnerability is high, threatening both application security boundaries and backend operations that rely on trusted client authorization tokens.
An attacker who successfully exploits this flaw achieves full execution capabilities within the security context of the victim's session. This permits access to session cookies, local storage objects, and API interaction secrets, allowing the attacker to spoof client sessions and query internal APIs.
Because the vulnerability operates entirely on client browsers upon loading a document, detection relies on network-level analysis or file-scanning mechanisms before the payload reaches the application interface.
The primary recommendation to resolve this vulnerability is to upgrade ngx-extended-pdf-viewer to version 29.0.0-rc.3 or higher. This release integrates patched core parsing utilities from pdf.js 6.2.108.
If immediate software upgrades are not possible, administrators must disable XFA parsing in the application setup module to remove the default exploit path:
pdfDefaultOptions.enableXfa = false;Furthermore, implementing a strict Content Security Policy (CSP) that prohibits inline scripts prevents injected DOM markup from executing successfully:
Content-Security-Policy: default-src 'self'; script-src 'self';CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
ngx-extended-pdf-viewer stephanrauh | >= 27.0.0-rc.0, < 29.0.0-rc.3 | 29.0.0-rc.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 / CWE-1103 |
| Attack Vector | Network |
| CVSS Score | 8.6 |
| Impact | Arbitrary JavaScript Execution (XSS) |
| Exploit Status | poc |
| KEV Status | No |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
jsoup is a widely used Java library for working with real-world HTML. Versions 1.14.3 up to but excluding 1.23.1 contain a Cross-Site Scripting (XSS) vulnerability. When an application configures a custom Safelist that explicitly permits certain raw-text or RCDATA elements, such as style, title, or iframe, an attacker can exploit a parser-browser desynchronization flaw to bypass sanitization. This is achieved by utilizing trailing ASCII control characters that are handled differently by the HTML5 parsing specification and Java's string normalization methods, resulting in unescaped markup execution on the client side.
A denial-of-service vulnerability in node-re2 prior to version 1.25.1 allows attackers to trigger uncatchable native assertion failures in the Google V8 engine. By supplying output-amplifying replacement templates, an attacker can exceed V8 string limits, resulting in an immediate process crash.
A medium-severity out-of-bounds (OOB) heap read vulnerability exists in node-re2 prior to version 1.26.1. When a raw binary Node.js Buffer with a truncated multi-byte UTF-8 character at its end is passed to the C++ native addon, the internal lookahead routine getUtf8CharSize() over-reads up to 3 bytes from the heap, leading to memory disclosure.
A critical OS command injection vulnerability exists in PHP_CodeSniffer's VCS blame report modules (Gitblame, Hgblame, Svnblame). Due to inadequate escaping of filenames passed to shell execution wrappers like popen(), an attacker who commits a file with a maliciously crafted name can execute arbitrary commands when the victim generates a blame report.
An authenticated stored Cross-Site Scripting (XSS) vulnerability exists in the Control Panel helper of Craft CMS before version 5.10.8. Due to lack of HTML entity encoding within the elementLabelHtml method, unescaped draft names are rendered directly into administrative interfaces.
A path traversal vulnerability exists in the local filesystem driver of Craft CMS. Due to validation occurring before path normalization, directory containment checks can be bypassed by utilizing specific protocol schemes like 'file://' along with directory traversal sequences. This allows authenticated users with administrative privileges to access or manipulate files outside the defined storage root directory.