Repository navigation
fix(rest): escape the API docs viewer URL value for its HTML attribute context (ruling 3C) - #25093
Conversation
…or its attribute context
The GET {base}/docs viewer page builds the sibling openapi URL from the
request path and placed it into a data-url attribute with no escaping. It is
now escaped for the HTML attribute context it lands in (ruling 3C on #25040),
via a small local escaper in packages/rest; a URL without attribute-interpreted
characters is served byte-identically. Adds html-outlets.pin.test.ts: a census
pinning this package's HTML outlet list, with a positive control, and a pin
that drives the real render path to assert the outlet escapes.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LmjU2x1faLZ39DVTFyVca6
📓 Docs Drift Check4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 19 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a3de2d749e8b9990be1f54a1383161c81af8f996 && git checkout a3de2d749e8b9990be1f54a1383161c81af8f996
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4feccc26851b89dcb8f4d78dfab011e73d12c128 afcf6ecbd5172aba86087ac09e53f25d2631eb21 && git checkout -B drift-repro 4feccc26851b89dcb8f4d78dfab011e73d12c128 && git merge --no-ff afcf6ecbd5172aba86087ac09e53f25d2631eb21
node scripts/docs-audit/affected-docs.mjs --json 4feccc26851b89dcb8f4d78dfab011e73d12c128 |
席位核对 · ACCEPT
Accepted deviations:
Landing: through the merge queue by this seat once every check on this head reads Generated by Claude Code |
Fixes #25077
The API docs viewer (
GET {base}/docs,packages/rest) builds the sibling openapi-document URL from the request and places it into a quoted HTML attribute of the served page. It interpolated that value into the attribute with no escaping, so a character the attribute context interprets reached the served markup as itself rather than as the matching HTML entity.Reach (abstract, per the #9387 disclosure ruling). Reachable by an authenticated request through a mounted host; an anonymous request is refused before the render. Measured through both
IHttpServerhosts this repo mounts these routes through. A URL carrying none of the interpreted characters is served byte-identically.The fix. The value is escaped for its HTML attribute context at that one outlet — ruling 3C on #25040: every outlet that renders a value into HTML escapes it by the context it lands in.
packages/resthad no HTML escaper; a package it depends on exports none and the repo's only escaper is private to another package this one does not import, so the fix adds a small local escaper inpackages/rest. It is not re-exported, so the package's published surface is unchanged. Normal URLs stay byte-identical.The outlet-list pin.
html-outlets.pin.test.tsenumerates this package's HTML outlets by a source scan, asserts the list equals the declared set (today: one), asserts the declared outlet escapes the value for its context, and carries a positive control proving the scan finds the known outlet. It matches the shape and name of PR #25076's per-package outlet-list pin.Evidence. The escaping pin is red on a hash-equal-restored ablation of the fix (the escaper reduced to identity) and green after; the byte-identical pin stays green under the identity ablation, as it should. The tests are named by what they assert — "a value carrying attribute-interpreted characters is escaped for the attribute context" and "an ordinary URL is served byte-identical" — and their inputs are the minimum characters the context interprets.
A
patchchangeset for@objectstack/restis included.Clause-②: no
Held off (out of scope): the page's other content;
packages/spec/**; PR #25076's files; the record export path (#25078, dispatched in parallel).Generated by Claude Code