Sep 19, 2026·7 min read·3 visits
The legacy DOC file parser in Flyfish File Viewer fails to sanitize hyperlink schemes before injecting them into anchor tags. Under typical execution flows, an attacker can embed malicious javascript: or vbscript: URIs into document links, executing arbitrary script in the host application's origin upon user click. This high-severity flaw (CVSS 8.2) is remediated in package versions starting with @file-viewer/doc 2.3.1.
This report details CVE-2026-91127 (GHSA-3753-m2x2-q623), a high-severity DOM Cross-Site Scripting (DOM XSS) vulnerability in the file-viewer workspace developed by flyfish-dev. The legacy Word document (.doc) parser fails to restrict hyperlink URI schemes when rendering extracted document targets into generated HTML. As a result, a remote attacker can construct a malicious legacy DOC file containing scripts inside hyperlink properties. When a user previews the file and clicks the hyperlink, arbitrary JavaScript executes in the context of the hosting origin, enabling session hijacking, credential theft, or unauthorized API interaction.
The file-viewer workspace by flyfish-dev is a client-side library designed to parse and render various document formats natively within browser environments. Key packages like @file-viewer/doc and msdoc-viewer allow internal applications to present Microsoft Office documents without relying on server-side document processing engines. This approach reduces server load but moves the entire security boundary of document parsing into the client's execution context. This library exposes an attack surface where untrusted user-supplied documents are parsed directly in the web browser.
The vulnerability identified as CVE-2026-91127 is a DOM-based Cross-Site Scripting (DOM XSS) flaw. It affects the legacy Word document (.doc) parsing and rendering logic, which is used for older binary formats. The weakness is classified under CWE-79 (Improper Neutralization of Input During Web Page Generation) and CWE-83 (Improper Neutralization of Script in Attributes in a Web Page).
An attacker can exploit this vulnerability by submitting a crafted legacy DOC file containing hyperlinks embedded with active or dangerous protocol schemes. If an application user views the rendered file and interacts with the link, the browser executes the payload. The execution occurs directly within the origin of the hosting web application, bypassing conventional sandbox structures.
The primary cause of CVE-2026-91127 is the failure of the @file-viewer/doc engine to validate or sanitize hyperlinked targets before outputting them to the Document Object Model (DOM). In legacy .doc files, hyperlinks are stored in raw binary properties. The parser extracts these URL values and maps them directly to the href attribute of HTML anchor elements (<a>) generated for document content.
While the renderer applied standard HTML entity escaping to the generated text, this measure only protects against structural DOM break-outs. HTML entity escaping (e.g., converting " to ") is insufficient for sanitizing attributes designed to receive URIs. Modern web browsers decode HTML entities in attribute values prior to parsing the URL scheme. Consequently, an obfuscated scheme like javascript:alert(1) is successfully resolved to javascript:alert(1) by the browser's HTML parser.
When a user clicks the rendered link, the browser initiates the protocol handler associated with the parsed scheme. If the scheme is javascript:, vbscript:, or data:, the browser evaluates the payload as active code. The execution inherits the full security context and privileges of the hosting application's origin, which violates the security assumptions of a native file viewer.
In vulnerable versions of @file-viewer/doc (prior to version 2.3.1), raw URL targets were integrated directly into the DOM tree. The fix implemented in commit ef045680f8d9830a3eee9612f7df46a734361b07 introduces a multi-tier defense scheme to address this issue. First, a centralized validation function named sanitizeMsDocLinkHref filters out dangerous URI patterns.
// Fixed version link validation logic
export function sanitizeMsDocLinkHref(
href: string | undefined | null,
policy: ExternalLinkPolicy = 'block',
): string | null {
// Strip control characters that browsers ignore but confuse filters (e.g., tabs, null bytes)
const value = String(href ?? '')
.replace(/[\u0000-\u0020\u007f-\u009f]/g, '')
.trim();
if (!value) return null;
if (value.startsWith('#')) return value; // Allow internal anchors/bookmarks
if (policy !== 'allow') return null; // Block external links by default
// Explicitly allow safe schemes only
if (/^(?:https?:|mailto:|tel:)/i.test(value)) return value;
// Prevent protocol-relative link exploitation (//attacker.com) and backslash paths
if (value.startsWith('//') || value.startsWith('\\')) return null;
// Allow safe relative paths
if (/^(?:\/|\.\/|\.\.\/)/.test(value) && !value.startsWith('//') && !value.startsWith('\\\\')) {
return value;
}
// Reject absolute paths that do not match the scheme allowlist
if (!/^[a-z][a-z\d+.-]*:/i.test(value) && !value.startsWith('\\')) return value;
return null;
}The second mitigation layer operates as a defense-in-depth measure during the DOM mounting phase in packages/renderers/doc/src/viewer.ts. The renderer incorporates DOMPurify (v3.4.13) to clean the generated HTML before inserting it into the application's document fragment.
// Sanitization at mounting boundary
export function sanitizeMsDocHtml(html: string, targetWindow: Window): DocumentFragment {
const purifier = createDOMPurify(targetWindow as unknown as WindowLike);
return purifier.sanitize(html, {
RETURN_DOM_FRAGMENT: true,
USE_PROFILES: { html: true },
FORBID_TAGS: ['base', 'embed', 'form', 'iframe', 'object', 'script', 'style', 'template'],
FORBID_ATTR: ['action', 'formaction', 'srcdoc'],
}) as unknown as DocumentFragment;
}This dual approach guarantees that even if a malicious URL passes the first filter, any dangerous elements or attributes are caught by DOMPurify before execution can occur. Additionally, by setting policy to 'block' by default, external hyperlinks are stripped entirely unless explicitly allowed by the application developer.
An attack leveraging CVE-2026-91127 requires the attacker to have a mechanism to deliver a crafted legacy .doc document to the target user. Common targets include document management systems, customer support portals, or internal collaboration platforms. The file must contain a hyperlink with a malicious protocol scheme.
An attacker can bypass basic string-matching filters in simple firewalls or basic parsing filters by employing various obfuscation techniques. For example, inserting control characters such as tabs or newline characters inside the protocol string can bypass naive signature detection while still being parsed correctly by client-side web browsers.
The official test suite demonstrates the vulnerability using a mock parsed document tree. In a vulnerable environment, processing a document block with an inline hyperlink configured with javascript:window.__rendererSentinel.doc += 10 results in an active link that executes the script upon user click. The script runs with full access to the origin's memory, cookies, and local storage.
The security impact of CVE-2026-91127 is rated as High, with a CVSS v3.1 score of 8.2. Although the vulnerability requires user interaction (clicking the link), the consequences of execution are substantial. The Scope is evaluated as Changed (S:C) because the security context shifts from a document-level rendering boundaries directly to the origin of the hosting application.
With the ability to execute arbitrary client-side scripts, an attacker can access sensitive information stored in the browser. This includes Session Cookies (unless marked HttpOnly), LocalStorage tokens, and session storage details. Attackers can leverage this access to perform unauthorized actions on behalf of the victim, such as modifying records, initiating transactions, or exfiltrating data via background HTTP requests.
Because this client-side viewer is commonly deployed in enterprise and internal portals, the vulnerability provides an initial access vector into internal corporate systems. A compromised browser session on an internal administration portal can allow an attacker to pivot into other systems behind the corporate firewall.
The primary remediation strategy for CVE-2026-91127 is upgrading all instances of the file-viewer components to their fixed releases. For workspaces utilizing individual packages, the library must be updated to @file-viewer/doc version 2.3.1, msdoc-viewer version 0.2.2, or @file-viewer/renderer-word version 2.3.2. Organizations utilizing package presets should migrate to version 2.3.4.
If immediate patching is not feasible, organizations can implement local workarounds to secure their platforms. One effective temporary measure is to configure the application's routing or document processing logic to block legacy .doc files entirely, or to force-download them rather than rendering them inline. Note that modern OpenXML formats (.docx) are handled by separate rendering modules and are unaffected by this vulnerability.
# Recommended defensive Content Security Policy header
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';Deploying a strict Content Security Policy (CSP) provides strong defense-in-depth. A policy that restricts script-src to 'self' and blocks inline scripts will prevent the browser from executing scripts embedded inside javascript: links, even if the application fails to sanitize the output properly.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@file-viewer/doc flyfish-dev | < 2.3.1 | 2.3.1 |
msdoc-viewer flyfish-dev | < 0.2.2 | 0.2.2 |
@file-viewer/renderer-word flyfish-dev | < 2.3.2 | 2.3.2 |
@file-viewer/preset-all flyfish-dev | < 2.3.4 | 2.3.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79, CWE-83 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 8.2 (High) |
| EPSS Score | N/A |
| Impact | DOM Cross-Site Scripting (DOM XSS) |
| Exploit Status | PoC (Proof-of-Concept) |
| KEV Status | Not listed |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
CVE-2026-77301 is a critical uncontrolled resource allocation vulnerability in the popular Node.js library adm-zip (versions prior to 0.6.1). During ZIP decompression of asynchronous entries, the library trusts the uncompressed size metadata declared in the central directory headers. Because Node.js's streaming zlib API completely ignores the maxOutputLength configuration, a crafted ZIP archive (decompression bomb) causes the application to continually allocate resident memory buffers on the heap without limits, causing rapid memory exhaustion and a process-level Out-of-Memory (OOM) crash.
An authorization bypass and tenant isolation vulnerability in Perses prior to version 0.54.0-beta.3 allows authenticated viewers to access unauthorized project resources by manipulating query parameters or querying unmapped ephemeral endpoints.
CVE-2026-63199 is a critical missing authorization vulnerability (CWE-862) in Perses versions 0.43.0 to 0.54.0-rc.0. It allows low-privileged attackers to retrieve and exfiltrate highly sensitive credentials (secrets) from different scopes by configuring a malicious datasource pointing to an attacker-controlled endpoint.
An arbitrary file read and path traversal vulnerability exists in Perses prior to version 0.54.0-rc.0. When configured with a file-system database backend, the application lacks input validation on the request-controlled project query parameter. An authenticated attacker with low privileges can supply directory traversal sequences to read arbitrary JSON or YAML files on the host file system.
CVE-2026-59163 is a critical authentication bypass vulnerability in the Mnemosyne sync server. In versions prior to v3.10.1, the server's authentication logic decoded incoming JSON Web Tokens (JWT) but completely skipped cryptographic signature verification. An unauthenticated remote attacker can exploit this vulnerability to bypass authentication, impersonate arbitrary users, read synchronized AI agent states, or write malicious database updates.
An authorization bypass vulnerability exists in the Moquette MQTT broker prior to version 0.18.1. When an MQTT client registers a Last Will and Testament (LWT) topic during its connection setup, the broker fails to perform write-access checks on that topic. Upon an abrupt client disconnection, the broker publishes the registered Will message to subscribers of the unauthorized topic, bypassing configured Access Control Lists (ACLs).