Skip to content

fix(docx-preview): sanitize hyperlink URIs to prevent XSS#158

Open
Mark-Zampedroni wants to merge 1 commit intomeganz:masterfrom
Mark-Zampedroni:fix/docx-hyperlink-xss
Open

fix(docx-preview): sanitize hyperlink URIs to prevent XSS#158
Mark-Zampedroni wants to merge 1 commit intomeganz:masterfrom
Mark-Zampedroni:fix/docx-hyperlink-xss

Conversation

@Mark-Zampedroni
Copy link

@Mark-Zampedroni Mark-Zampedroni commented Mar 13, 2026

What

Adds protocol validation to renderHyperlink in docx-preview.js to prevent potential XSS via crafted DOCX hyperlinks.

Why

The renderHyperlink function sets result.href directly from the DOCX relationship target without validating the URI scheme. A DOCX file with a javascript: hyperlink gets rendered as a clickable <a href="javascript:..."> in the preview iframe.

The preview iframe is about:blank, same-origin, and has no sandbox attribute, so any script execution would run in the context of mega.nz with full access to the session.

Currently CSP blocks execution, but there's no code-level protection. For reference, renderSymbol in the same file already has an explicit XSS prevention check (with the comment mega.nz production build: prevent xss/html-injection), so this is an oversight in an adjacent function.

Fix

Instead of assigning href immediately, the value is first validated against a protocol whitelist (http:, https:, mailto:). Non-matching URIs (like javascript:, data:, vbscript:) are silently dropped. The <a> element is still rendered but without an href, so the document structure is preserved.

Example

A minimal DOCX with a malicious hyperlink relationship in word/_rels/document.xml.rels:

<Relationship Id="rId666"
  Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
  Target="javascript:void(alert('XSS: '+document.domain))"
  TargetMode="External"/>

Referenced in word/document.xml:

<w:hyperlink r:id="rId666">
  <w:r><w:t>Click here</w:t></w:r>
</w:hyperlink>

Before fix: the preview iframe renders <a href="javascript:void(alert('XSS: '+document.domain))">Click here</a>

After fix: the <a> tag is rendered without the dangerous href since javascript: doesn't match the allowed protocols.

Copy link
Contributor

@diegocr diegocr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Mark-Zampedroni, thanks for your PR!

Ideally however, you should be submitting this on the upstream repository at https://github.com/VolodymyrBaydalka/docxjs

Later on, once your changes are merged, we will sync our fork with them.

You're editing a vendor file whose changes might be lost, since there's a bundling process with that file automatically generated.

Alternatively, if they don't accept your changes, you could submit this on our fork, but we will anyway consider applying them there either way - thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants