[WEB-7888] fix(security): normalize href before protocol check in CustomLinkExtension (GHSA-v2vv-7wq3-8w2j) (#9313)

* [WEB-7888] fix(security): normalize href before protocol check in CustomLinkExtension (GHSA-v2vv-7wq3-8w2j)

The existing startsWith("javascript:") guard in parseHTML() and renderHTML()
is bypassable with a whitespace prefix (e.g. "\tjavascript:alert(1)"). Per the
WHATWG URL spec, browsers strip ASCII Tab/LF/CR from URL strings during parsing,
so the whitespace-prefixed href passes the guard, is rendered into the DOM
verbatim, and executes when clicked (browser strips the tab → javascript: fires).

Add isDangerousHref() helper that strips Tab/LF/CR and leading C0 controls
before the protocol check, replicating the browser's normalization. Replace
both naive startsWith checks in parseHTML() and renderHTML() with this helper.

Add a defence-in-depth guard in clickHandler.ts that rejects
javascript:/data:/vbscript: hrefs before window.open() — link.href is the
browser-resolved URL (whitespace already stripped), so a regex check there
catches any URI that bypasses the parse/render-time guards.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-7888] fix: align clickHandler blocked-scheme list with isValidHttpUrl policy

Add file: and about: to the clickHandler protocol guard to match the
blocked-scheme contract in isValidHttpUrl, avoiding policy drift.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
This commit is contained in:
Manish Gupta
2026-07-09 18:30:54 +05:30
committed by GitHub
parent 14a4c22f94
commit 73e360844b
2 changed files with 10 additions and 0 deletions

View File

@@ -40,6 +40,16 @@ export function clickHandler(options: ClickHandlerOptions): Plugin {
const target = link?.target ?? attrs.target;
if (link && href) {
// Defence-in-depth: link.href is the browser-resolved URL (whitespace
// already stripped by the browser's WHATWG URL parser), so a protocol
// check here is sufficient to catch any dangerous URI that slipped past
// the editor's parse/render-time guards. Matches the blocked-scheme list
// in isValidHttpUrl (javascript:, data:, vbscript:, file:, about:)
// to keep the policy consistent (GHSA-v2vv-7wq3-8w2j).
if (/^(javascript|data|vbscript|file|about):/i.test(href)) {
return false;
}
window.open(href, target);
return true;