Skip to content

fix(files): allowlist the schemes a markdown link may target - #7012

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/markdown-link-scheme-allowlist
Aug 23, 2026
Merged

fix(files): allowlist the schemes a markdown link may target#7012
waleedlatif1 merged 1 commit into
stagingfrom
fix/markdown-link-scheme-allowlist

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • normalizeLinkHref rejected only file for a scheme:// target and returned every other scheme unchanged. scheme:// is well-formed for any scheme, so a blocklist can't be complete here — switched it to an allowlist of http(s), ftp(s), mailto, tel.
  • The rendered anchor for a linked image is built from a node attribute rather than a link mark, so the editor's own URI validation never inspects it. That made this function the step deciding whether such a target reaches the DOM.
  • Committing an edit whose target normalizes away no longer unsets the link. The edit field is seeded with the current href, so committing an untouched one used to delete a link the user had only opened; refusing a target isn't the same instruction as removing one. Clearing the field still removes the link.
  • Collapsed the scheme check to a single regex and dropped the now-unused one, matching how the other rules in the file are written.

Type of Change

  • Bug fix

Testing

  • Added coverage for the slash-bearing and unknown-scheme cases, a property test over the paddings and interior whitespace a browser strips before resolving a scheme, a test that a linked image's target is refused before it can become an anchor, and tests for all three applyLink outcomes. Each was verified to fail against the previous behavior.
  • Confirmed no effect on stored documents: normalization runs on the render and edit paths only, never on parse or serialize, so a refused target still round-trips byte-identical. Verified across 21 schemes.
  • Relative, anchor, protocol-relative, bare-domain, and host:port handling are unchanged, as are sim: mention links, which take a different branch.
  • bun run type-check, bun run lint and the full bun run check:audits (33 audits) pass; 770 tests in the affected area pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

`normalizeLinkHref` rejected only `file` for a `scheme://` target, so any other
scheme was returned unchanged. `scheme://` is well-formed for every scheme, so
the check let through spellings that are not navigable targets at all.

- Keep a scheme only when it is http(s), ftp(s), mailto, or tel; drop the rest
- Leave an existing link alone when a committed target normalizes away, rather
  than unsetting it — the editor seeds that field with the current href, so
  committing an untouched one previously removed the link

Detection is unchanged for relative, anchor, protocol-relative, and bare-domain
targets. A document's stored markdown is untouched: normalization runs on the
render and edit paths, never on parse or serialize, so a target that is refused
still round-trips verbatim.
@vercel

vercel Bot commented Aug 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 23, 2026 11:57am

Request Review

@cursor

cursor Bot commented Aug 23, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches XSS-relevant href sanitization in the markdown editor. The change is a tightening of existing checks with tests, not a new auth or data path.

Overview
Closes a hole in normalizeLinkHref: scheme:// was treated as a network URL and only file was blocked, so javascript://… and unknown schemes could still become clickable anchors (including linked images, whose href lives on a node attr, not a link mark).

Schemes are now allowlisted (http(s), ftp(s), mailto, tel). Everything else is dropped to '' so callers render inert text. Relative, hash, protocol-relative, and host:port handling is unchanged.

applyLink no longer unsets the mark when a non-empty target normalizes away — refusing an unsafe href is not the same as clearing the field. Tests cover slash-bearing/unknown schemes, whitespace smuggling, linked-image targets, and the three applyLink outcomes. Normalization still does not rewrite stored markdown.

Reviewed by Cursor Bugbot for commit 383c010. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces markdown link scheme blocklisting with an explicit allowlist and distinguishes clearing a link from refusing an unsafe target.

  • Allows only HTTP(S), FTP(S), mailto:, and tel: explicit schemes while preserving relative, protocol-relative, and host-port handling.
  • Prevents refused linked-image targets from becoming anchors.
  • Keeps an existing link unchanged when an untouched nonempty target is refused, while explicit clearing still removes it.
  • Adds normalization, linked-image, round-trip, and link-editing outcome coverage.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issues identified.

The allowlist closes the unsafe explicit-scheme path across the known render and editing callers, and the revised edit behavior preserves links only when a refused nonempty target is submitted while explicit clearing continues to remove them.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/markdown-fidelity.ts Replaces permissive explicit-scheme handling with a focused safe-scheme allowlist while retaining established relative and bare-host behavior.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/menus/link-editing.tsx Separates explicit link removal from rejection of a nonempty unsafe target so opening and committing an unchanged refused link does not delete it.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/menus/link-editing.test.ts Covers setting, clearing, and refusing links through the shared applyLink helper.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/round-trip.test.ts Expands coverage for unknown and executable schemes, browser-normalized whitespace variants, and linked-image target sanitization.

Reviews (1): Last reviewed commit: "fix(files): allowlist the schemes a mark..." | Re-trigger Greptile

@waleedlatif1
waleedlatif1 merged commit f386769 into staging Aug 23, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/markdown-link-scheme-allowlist branch August 23, 2026 17:31
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.

1 participant