Skip to content

security: restrict link and update-banner URLs to safe schemes#59

Merged
sam-powers merged 1 commit into
mainfrom
security/url-scheme-allowlists
Jun 13, 2026
Merged

security: restrict link and update-banner URLs to safe schemes#59
sam-powers merged 1 commit into
mainfrom
security/url-scheme-allowlists

Conversation

@sam-powers

Copy link
Copy Markdown
Owner

What

Two places trusted a URL more than they should.

  • normalizeHref (the Cmd+K link mark) passed through any explicit scheme, so javascript: and data: could be persisted into the saved .md and later clicked — a stored script-execution vector in a shared document. It now allows only http/https/mailto/tel (plus in-page and relative refs); any other scheme returns empty.
  • The update banner's "View release" button opened the html_url from GitHub's API response verbatim. It now accepts that URL only if it parses as an https://github.com/ URL, falling back to the hardcoded releases page otherwise — a spoofed or compromised response can't redirect the user to an arbitrary scheme or host.

Tests

Added coverage for the rejected link schemes (javascript/data/vbscript/file, case-insensitive) and for html_url fallback on both a dangerous scheme and a non-github host. Full bar green: typecheck, eslint, prettier, vitest (235).

🤖 Generated with Claude Code

Two places trusted a URL more than they should:

- normalizeHref (Cmd+K link mark) passed through any explicit scheme,
  so javascript: and data: could be persisted into the saved .md and
  later clicked — a stored script-execution vector in a shared document.
  It now allows only http/https/mailto/tel (plus in-page and relative
  refs); any other scheme returns empty.
- The update banner's "View release" button opened the html_url from
  GitHub's API response verbatim. It now accepts that URL only if it
  parses as an https://github.com/ URL, falling back to the hardcoded
  releases page otherwise, so a spoofed or compromised response can't
  redirect the user to an arbitrary scheme or host.

Adds coverage for the rejected schemes (javascript/data/vbscript/file)
and for html_url fallback on a dangerous scheme and a non-github host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sam-powers sam-powers merged commit 01031f8 into main Jun 13, 2026
3 checks passed
@sam-powers sam-powers deleted the security/url-scheme-allowlists branch June 13, 2026 21:55
sam-powers added a commit that referenced this pull request Jun 13, 2026
Documents Quill's security posture for a reviewing engineer: the threat
model (deep link as the one attacker-influenced entry point; deserialized
data trusted more than rendered data), the four merged hardening measures
(#57 path confinement + deep-link validation, #58 annotation sanitization,
#59 URL scheme allowlists, #60 binary-resolution hardening), and the two
deliberate non-fixes left in place with rationale (asset-protocol $HOME/**
scope, remote-image beacon).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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