Skip to content

RSS link URLs from Notion not validated for scheme — javascript: XSS possible in feed output #174

@ooloth

Description

@ooloth

Current state

io/notion/renderBlocksToHtml.ts line 71 interpolates rich text link URLs from Notion directly into href attributes in the RSS feed HTML:

if (item.link) text = `<a href="${item.link}">${text}</a>`

The link field is validated by z.url(), but Zod's z.url() delegates to the JavaScript URL constructor, which accepts javascript: as a valid scheme. A Notion-authored link with a javascript: URL passes validation and is rendered verbatim in the RSS output. RSS reader applications that render HTML (Feedly, NetNewsWire, etc.) may execute the script when the link is clicked.

The same unescaped URL interpolation applies to image and video block URLs on lines 54–56, which are also interpolated into src and href attributes without HTML-encoding — a URL containing " can break out of the attribute context.

Ideal state

  • Before interpolating any URL into an href or src attribute, the renderer checks that the scheme is http: or https:.
  • A javascript:, data:, or any other non-HTTP/HTTPS URL from Notion produces no <a> or <img> tag in the RSS output.
  • All URL values are also HTML-encoded (replacing " with &quot;) before attribute interpolation.

Starting points

  • io/notion/renderBlocksToHtml.ts line 71 — the href="${item.link}" interpolation in the rich text renderer
  • io/notion/renderBlocksToHtml.ts lines 54–56 — src="${block.url}" and href="${block.url}" for image and video blocks

QA plan

  1. Author a Notion page with a rich text link whose URL is javascript:alert(1). Fetch the RSS route. Inspect the generated HTML — confirm no <a href="javascript:..."> appears in the output.
  2. Author a link with data:text/html,<script>alert(1)</script>. Confirm it is also blocked.
  3. Author a link with a URL containing a double-quote (e.g. https://example.com/?a="b"). Inspect the rendered HTML — confirm the quote is HTML-encoded and does not break the attribute.
  4. Author a valid https://example.com link. Confirm it renders correctly as <a href="https://example.com">.

Done when

No javascript:, data:, or non-HTTP/HTTPS URL from Notion can appear as an href or src attribute value in the RSS feed output, and all URLs are HTML-encoded before attribute interpolation.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions