Skip to content

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

Open
mguptahub wants to merge 2 commits into
previewfrom
web-7888/custom-link-xss
Open

[WEB-7888] fix(security): normalize href before protocol check in CustomLinkExtension (GHSA-v2vv-7wq3-8w2j)#9313
mguptahub wants to merge 2 commits into
previewfrom
web-7888/custom-link-xss

Conversation

@mguptahub

@mguptahub mguptahub commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds isDangerousHref() helper in extension.tsx that strips ASCII Tab/LF/CR and leading C0 controls from a raw href before the protocol check, replicating the WHATWG URL spec's whitespace normalization
  • Replaces both naive startsWith("javascript:") checks in parseHTML() and renderHTML() with isDangerousHref() — blocks whitespace-prefixed bypasses like "\tjavascript:alert(1)"
  • Adds a defence-in-depth guard in clickHandler.ts that rejects javascript:/data:/vbscript: protocols before window.open()link.href is the browser-normalized URL so this catches any edge case that slips past parse/render-time guards

Security context

Advisory: GHSA-v2vv-7wq3-8w2j | Severity: High | CWE-79 (Stored XSS)

CustomLinkExtension blocked javascript: hrefs with a naive startsWith check. Per the WHATWG URL spec, browsers strip ASCII Tab (U+0009), LF (U+000A), and CR (U+000D) from URL strings before parsing — so "\tjavascript:alert(1)" passes the guard, is stored and rendered verbatim, and when a victim clicks the link the browser strips the tab and executes javascript:alert(1) in the application's security context. A Guest-level member can author the payload via the REST API; any higher-privileged user who clicks it is compromised.

Files changed

  • packages/editor/src/core/extensions/custom-link/extension.tsx
  • packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts

Test plan

  • Post a comment via API with <a href="\tjavascript:alert(document.cookie)">click me</a> — verify the link does not execute JS when clicked in the editor
  • Post a comment with a plain javascript:alert(1) href — verify it is still blocked (existing behaviour unchanged)
  • Post a comment with a normal https://example.com link — verify it opens correctly
  • Verify relative links (e.g. #section) and mailto links still work
  • Test with \njavascript: and \rjavascript: variants (LF/CR prefix)

Summary by CodeRabbit

  • Bug Fixes
    • Improved link safety by blocking clicks on links that use unsafe URI schemes, such as javascript:, data:, and vbscript:.
    • Unsafe links are now prevented from opening in a new window or tab, with additional protection for file: and about: schemes.

…tomLinkExtension (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>
Copilot AI review requested due to automatic review settings June 25, 2026 06:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@makeplane

makeplane Bot commented Jun 25, 2026

Copy link
Copy Markdown

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

React Doctor found no issues. 🎉

Reviewed by React Doctor for commit d333d2c.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5f08e8c1-7365-4975-ae21-2ae3a2c6155b

📥 Commits

Reviewing files that changed from the base of the PR and between 3387e24 and d333d2c.

📒 Files selected for processing (1)
  • packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts

📝 Walkthrough

Walkthrough

The custom link click handler now checks resolved href values for unsafe URI schemes before opening a new window. Matching javascript:, data:, vbscript:, file:, or about: links return false instead of calling window.open.

Changes

Unsafe link scheme guard

Layer / File(s) Summary
Href scheme validation
packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts
The click handler tests the resolved href for javascript:, data:, vbscript:, file:, and about: schemes before calling window.open, and returns false when a match is found.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through links both near and far,
But skipped the ones that aren’t safe by star.
No tricky schemes can make me stray,
I bounce on open windows the wholesome way.
Nibble, hop, and safely go!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific and accurately summarizes the security fix in CustomLinkExtension.
Description check ✅ Passed The description covers the change, security context, affected files, and test plan, with only a few optional template sections omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch web-7888/custom-link-xss

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts`:
- Line 48: The blocked-scheme check in clickHandler.ts is narrower than the
shared URL policy used by isValidHttpUrl, so unsafe schemes like file: and
about: can still slip through. Update the href validation in clickHandler to
reuse the shared validator (preferred) or expand the scheme block to match
isValidHttpUrl’s contract, keeping the policy consistent with the existing URL
safety rules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4c9bbe5-74b8-4431-bda8-df953d8baea6

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8f363 and 3387e24.

📒 Files selected for processing (2)
  • packages/editor/src/core/extensions/custom-link/extension.tsx
  • packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts

Comment thread packages/editor/src/core/extensions/custom-link/helpers/clickHandler.ts Outdated
…tpUrl 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>
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