Skip to content

Harden XSS URL checks, first-run docs, and CI - #1

Merged
cursor[bot] merged 1 commit into
mainfrom
cursor/harden-xss-and-first-run-d42c
Aug 13, 2026
Merged

Harden XSS URL checks, first-run docs, and CI#1
cursor[bot] merged 1 commit into
mainfrom
cursor/harden-xss-and-first-run-d42c

Conversation

@andersyin

Copy link
Copy Markdown
Owner

Summary

CI on main was already green (Playwright 34/34). The claimed XSS hardening and first-run path were not:

  • safeUrl only stripped C0 whitespace, so ZWSP / : / %3A could still produce javascript:-like href/src.
  • The empty state told people to run 打开阅读器.command, a file that does not exist (open-reader.command does).
  • G (scroll to bottom) was dead code: e.key === 'g' || e.key === 'G' always won first.

This PR hardens the sanitizer, fixes those first-run/docs bugs, and adds a cheap Node check so XSS regressions do not require Chrome. No new reader features.

Type of change

  • Bug fix
  • New feature
  • Documentation improvement
  • Other (XSS hardening, CI)

What changed

XSS / hardening

  • Normalize URLs before the protocol check (Unicode format/whitespace, HTML entities, percent-encoding). Reject protocol-relative //.
  • CSP (script-src nonce, connect-src 'none') and Referrer-Policy: no-referrer so file:// pages do not leak local paths when markdown has remote images.
  • AI sidecar key_points / conclusions / action_items coerced with asList so a string/object field cannot throw .map.

First-run

  • Empty state names bash open-reader.command notes.md and leads with drag-and-drop.
  • Launcher: require python3, portable open / xdg-open, warn when there is no bundle yet, do not abort after a successful bundle if the desktop opener fails.

CI / tests

  • Node 22, permissions: contents: read, bash -n + ShellCheck on open-reader.command.
  • test/sanitize.mjs (no browser) covers camouflage vectors, fixture render, CSP/zero-CDN, empty-state filename.
  • Playwright Phase D now asserts the xss-sample.md fixture and edit-injected camouflage (37 assertions).

Docs

  • Honest limitation: reader chrome is offline; http(s) images inside markdown still fetch. README JSON sidecar example is valid JSON. File tree lists CONTRIBUTING / CI / sanitize.mjs.

Testing

bash -n open-reader.command
shellcheck --severity=warning --format=gcc open-reader.command   # clean
node test/sanitize.mjs                                           # 48 passed
node test/generate-bundle.mjs
node test/heartbeat_v16.mjs                                      # 37 passed

Please confirm GitHub Actions is green on this PR before merging. After merge, a smoke test is: double-click md-reader.html, drag in a .md file, and on macOS bash open-reader.command notes.md.

Checklist

  • No external dependencies added (zero-dep policy)
  • XSS hardening maintained (if HTML/JS changes)
  • Tested in Chrome/Chromium via Playwright (not a second GUI browser)
  • README updated if needed

Do not merge until you have reviewed — this is the next repo after video-analysis-gemini.

Open in Web Open in Cursor 

Reject camouflaged javascript: URLs (ZWSP, HTML entities, percent-encoding),
fix Shift+G, and point the empty state at open-reader.command.

Co-authored-by: andersyin <andersyin@users.noreply.github.com>
@andersyin
andersyin marked this pull request as ready for review August 13, 2026 04:53
@cursor
cursor Bot merged commit a428209 into main Aug 13, 2026
1 check passed
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