Skip to content

id(web): neutralize executable URL schemes in imported Markdown links #5745

Closed

Description

@dezren39

Problem

Markdown converted for the ID web surface copies Comrak link URLs into HTML href attributes without rejecting executable schemes. In pkgs/id/src/web/markdown.rs around lines 2985-2995, imported or collaborative Markdown can contain a link such as open; when rendered and clicked in the same-origin application, the javascript URL runs in the user's browser context. The collab document path reaches this renderer via pkgs/id/src/web/collab.rs:141-153.

Existing renderer tests cover safe schemes but not javascript: (markdown.rs around lines 5808-5829 and 5879-5899). The /blob active-content mitigation in #908/#919 is related precedent but does not cover these editor links.

Required behavior

Only render URLs from an explicit safe set; neutralize executable or unknown schemes such as javascript:, data:, and vbscript:. Preserve safe http, https, mailto, and relative/internal links. Do not rely on browser sanitization.

Acceptance criteria

  • A regression test renders a javascript: link and proves it cannot produce an executable href.
  • Cases cover data:, vbscript:, protocol-relative, relative, http, https, and mailto, with a documented allowed-scheme oracle.
  • Collaborative Markdown rendering uses the same sanitizer as other Markdown entry points.
  • Existing safe-link behavior and formatting are unchanged.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/highImportant and time-sensitive
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Nov 5, 2026
  2. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor
  3. added a commit that references this issue on Nov 5, 2026
    49aad00
  4. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 5, 2026
  5. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    Triage findings — issue #5745 is a live stored-XSS-class bug

    Verified fresh against GitHub main c26e0585add3 (not the packet's stale line numbers alone):

    1. Verbatim href copy, no scheme check. pkgs/id/src/web/markdown.rs, NodeValue::Link arm (line 2988 at that sha): let mut attrs = json!({"href": link.url}); — the Comrak URL goes straight into the ProseMirror link mark. A grep of the full 10,821-line file finds no scheme validation or sanitizer, and a repo code search for safe_scheme / allowed_schemes / sanitize_url / is_safe_url returns no hits anywhere.
    2. Emit side is the same. At ~4972–4984 the save path builds <a href="..."> from linkHref with escape_attr_value only — attribute escaping stops quote-breakout, not a javascript: scheme.
    3. Collab path reaches it. pkgs/id/src/web/collab.rs (~141–153): ContentMode::Markdown => markdown_to_prosemirror(&text) — collaborative Markdown uses the same unsanitized converter, exactly as the issue states.
    4. Test gap is real. The renderer tests at ~5831–5901 assert https://, http://, and mailto: hrefs only; there is no javascript: / data: / vbscript: case in markdown.rs.
    5. No competing work. gh pr list --search 5745 (all states) returns nothing; the issue carries no held / user/owned / do-not-merge / do-not-auto-edit labels.

    Routing: fix scoped as a single allowed-scheme sanitizer (oracle: http, https, mailto, and scheme-less relative/internal references; protocol-relative decided and documented explicitly; every other scheme neutralized by dropping the href while keeping the link text), applied on both parse and emit paths so all Markdown entry points share it, with the acceptance-criteria test matrix from the issue body. Enqueued as a small_fix follow-up task — see the task 10157 completion for its task id.

  6. added
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  7. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor

    🤖 Agent note · picked up

  8. 10 remaining items

  9. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 5, 2026
  10. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  11. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: done (already_done — verified merged/closed)
    queue: repo-health-code-pilot
    task: 10643 (small_fix; worker repo-worker-code; lane code-z)
    by: repo-queue-worker-shift-z
    at: 2026-11-05T19:14Z

    Fresh verification (gh, 2026-11-05T19:13Z): issue #5745 is CLOSED and PR #6339 is MERGED at 2026-11-05T18:44:08Z (merge commit d492d6a). The work this task tracked is landed; the task's awaiting_ci checkpoint is superseded by the merge. Completing task 10643 as already_done with this evidence. The image-src half of the same converter gap is tracked separately as issue #6364 / fix task 10725.

  12. removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)kind/bugSomething isn't working (prefixed form of the classic bug label)priority/highImportant and time-sensitivestatus:donetask/small-fixQueue packet kind: bounded fix with reproduction and targeted teststask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions