fix(html): filter a document hyperlink through the scheme allowlist - #756
Merged
Conversation
`translate_link` wrote a link's target through `escape_attribute` and nothing else, so a `javascript:` href in an odt, docx, pptx, xlsx or markdown reached the rendered page and ran script in whatever origin serves it. Markdown is what made that cheap to reach: no container to build, and the format most likely to be user-authored untrusted text. The allowlist a PDF `/URI` action already went through moves from `html/pdf_file.cpp` into `html/common.*` and both callers use it, which leaves one policy instead of two. A refused target loses its `href` and keeps its text and styling; `Link::href()` is untouched. Fixes #737 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Re7MMYiM7fL58uELzKGy77
andiwand
force-pushed
the
fix/link-scheme-allowlist
branch
from
August 29, 2026 08:01
5acebc0 to
8aeedd0
Compare
andiwand
enabled auto-merge (squash)
August 29, 2026 08:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code
Fixes #737.
translate_linkwrote a link's target throughescape_attributeand nothing else, so the scheme stayed live: ajavascript:href in an odt, docx, pptx, xlsx or markdown reached the rendered page and ran script in whatever origin serves the generated html. Entity-obfuscated variants landed there too —[a](javascript:alert(1))— because the numeric reference is resolved before the href is stored, so the filter has to run after that resolution, which this one does.AGENTS.mdalready recorded this as the one place the html output's policy was inconsistent. It is now one policy:is_safe_urimoves out ofhtml/pdf_file.cppintohtml/common.*, unchanged — the six navigable schemes (http,https,mailto,ftp,ftps,tel) plus scheme-less references, reading the scheme past embedded whitespace and control bytes sojava\tscript:cannot slip through.translate_linkcalls it, and a refused target loses itshrefrather than becoming#or plain text — the smallest change, and the link keeps its text and its styling.pdf_file.cppcalls the same function from the same place it did before.Link::href()on the element api is unaffected; this is only about what the renderer emits.The allowlist was not widened for documents.
file:was the candidate — the corpus has nofile:hyperlink in it, and afile:href is exactly the one that matters in a webview serving generated html from a local origin, so keeping it out costs nothing and avoids re-opening the two-policy split.Test
html_common.*— four unit tests over the lifted function: the navigable schemes, scheme-less references, the refused schemes, and whitespace/NUL inside a scheme.html.a_link_the_page_must_not_navigate_to_loses_its_href/..._keeps_its_href— end to end through the renderer on the issue's own repro, including the numeric and hex entity forms.javascript:void(0)links (physics.docx, its reflow variant,style-missing+image-1.odt); every other byte is identical, and the pins intest/data.cmakeare advanced to the regenerated commits.