fix(docs): a posted doc cannot run script on the Booth's origin
Found by design-dev's impeccable run and confirmed at source. Python-Markdown passes raw HTML through, and doc.html and booth.html render the result |safe. A <script> in any session's .md ran on the Booth's origin, and a contract that quoted <pre> opened a real one and swallowed the rest of the doc. Operator ruling: escape raw HTML (not an allowlist). - render_doc deregisters Python-Markdown's block and inline HTML processors, so raw HTML reaches the serializer as text and is escaped there. Fenced and inline code are unchanged. - Every link href in a doc goes through links.is_safe_href after browser-style decoding. Python-Markdown keeps character references in attributes, so `javascript:` reached the browser as `javascript:`. - is_safe_href reads a backslash as a slash, as a browser does in an http(s) URL: `/\evil.test` is `//evil.test`. This also closes the hole on the link board. - A render that raises falls back to raw text, which the template escapes. Two of 19 live .md files render differently. One is a contract losing the quoted <pre> that swallowed it. The other is links.md, which renders as a board, not through render_doc. heid bug-hunt panel (4/4): the core claim held. Its two concrete edges (the backslash twin, the unbounded render) are fixed here. Table tests/mutations/doc_html.toml: 9/9 proved. Suite 951 -> 975.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# 2026-09-28 — A posted doc could run script on the Booth's origin
|
||||
|
||||
**Found by design-dev's impeccable run** (the whole-surface audit Prime asked
|
||||
for, report booth `booth-antislop`), confirmed at source by booth-dev:
|
||||
Python-Markdown passes raw HTML through and `doc.html` / `booth.html` render it
|
||||
`|safe`. Any session's `.md` could carry a `<script>`; a contract that merely
|
||||
QUOTED `<pre>` opened a real one and swallowed the rest of the doc.
|
||||
|
||||
**Operator ruling (Prime, in this session: "A"; and in design-dev's): ESCAPE
|
||||
raw HTML, not an allowlist** — the live docs that carry tags mean the literal
|
||||
tag, and an allowlist would still turn a quoted `<pre>` into a real one.
|
||||
Measured before shipping: 2 of 19 live `.md` files render differently; one is
|
||||
`booth-redesign/03-u1-item-record.contract.md` losing exactly the swallowing
|
||||
`<pre>`, the other is `links/links.md`, which renders as a board and never
|
||||
through `render_doc`.
|
||||
|
||||
**Found while fixing it, same class:** markdown link hrefs were never checked,
|
||||
and Python-Markdown keeps character references in attributes, so
|
||||
`[x](javascript:...)` reached the browser as `javascript:`. Every doc href
|
||||
now goes through `links.is_safe_href` after browser-style decoding
|
||||
(`_browser_href`). mailto autolinks lose their href as a result; accepted.
|
||||
|
||||
**The heid panel (4/4, thread `01M3MFG07JCAJTQXRBC1GKS2FG`) said the core
|
||||
claim holds** and found its edges: `/\evil.test` passed `is_safe_href` as a
|
||||
relative path although a browser reads it as `//evil.test` (fixed in the ONE
|
||||
predicate, so the board is closed too); no bound around the render (fixed:
|
||||
a raising render falls back to escaped raw text, which also covers a markdown
|
||||
upgrade renaming the deregistered processors — the tests would go red on that
|
||||
upgrade). Declined: emphasis still applying inside quoted HTML (`**x**` in a
|
||||
quoted attribute renders bold) — that is prose getting markdown; quote in a
|
||||
code span for byte-literal. Accepted: `img@src` unguarded (inert in current
|
||||
browsers; data: images are legitimate), `html.unescape` as a superset of
|
||||
attribute decoding (over-refuses at worst).
|
||||
|
||||
**Guards not claimed as falsifiers:** the tab/CR/LF drop and C0 trim in
|
||||
`_browser_href`, because Python 3.13's urlsplit does the same; the
|
||||
AMP_SUBSTITUTE restore, reachable only through automail (always `mailto:`).
|
||||
Table: `tests/mutations/doc_html.toml`, 9/9 proved.
|
||||
Reference in New Issue
Block a user