1# Markdown is anyone's who can push a repo, and a diagram's text goes into2# the page as SVG: none of it can run a script, load anything, restyle the3# page or link anywhere but where links may go. Pele escapes and filters4# it, and its SVG passes a sanitizer that keeps only what Pele draws with;5# SVG written straight into the markdown is still dropped.6. "$(dirname "$0")/../lib.sh"7user dami8repo dami/greet9clone dami dami/greet "$T/w/d"10cat >"$T/w/d/README.md" <<'EOF'11# greet1213```mermaid14---15title: "<script>alert('title')</script>"16---17%%{init: {"themeCSS": "body { display: none }", "fontFamily": "x;background:url(https://evil.example/f)"}}%%18flowchart LR19 accTitle: </title><script>alert('acc')</script>20 A["<script>alert(1)</script>"] --> B["<img src=x onerror=alert(2)>"]21 B --> C["</text></svg><style>body{display:none}</style>"]22 C --> D["#lt;a href=#quot;javascript:alert(3)#quot;#gt;x#lt;/a#gt;"]23 D --> E@{ img: "https://evil.example/pixel.png", label: "img" }24 click A "javascript:alert(4)"25 click B href "data:text/html,<script>alert(5)</script>"26 click C "//evil.example/x"27 click D "docs/guide.md" "tip"28 style A fill:red,stroke:#000,font-family:x29 classDef box fill:#f9f30 class B box31```3233<svg onload="alert(6)"><rect width="9999" height="9999"/><a href="javascript:alert(7)"><text>raw</text></a></svg>34EOF35at "$T/w/d" commit "first" docs/guide.md36push_as dami "$T/w/d" origin main37build38p=$FORGE_WWW/dami/greet/index.html39fig=$(grep -o '<figure class="diagram">.*</figure>' "$p")40[ -n "$fig" ] || fail "no diagram on $p"41tags() { printf '%s' "$fig" | grep -oE '<[^>]*>'; }42# Only Pele's shapes, text and links: no script, style, image or foreign43# object, and no attribute but these.44eq "$(tags | grep -oE '^<[a-z]+' | LC_ALL=C sort -u | tr '\n' ' ')" '<a <figure <g <path <rect <svg <text <title <tspan '45eq "$(tags | grep -oE ' [a-zA-Z:-]+=' | tr -d ' =' | LC_ALL=C sort -u | tr '\n' ' ')" 'aria-labelledby aria-roledescription class d fill font-weight height href id rel role stroke stroke-linecap style text-anchor transform viewBox width x xml:space xmlns y '46if tags | grep -qi 'url('; then fail "a url() in the diagram"; fi47# One link: the relative one, resolved to the forge's page. javascript:,48# data: and network-path links are dropped.49eq "$(tags | grep -oE '<a [^>]*>' | sort -u)" '<a href="/dami/greet/blob/main/docs/guide.md/" rel="noopener">'50# Inline styles keep only drawing properties; classDef names don't reach51# the page's classes.52eq "$(tags | grep -oE ' class="[^"]*"' | sed 's/ class="//; s/"$//' | tr ' ' '\n' | grep -vE '^(pele(-[a-zA-Z-]+)?|clickable|diagram)$' | sort -u)" ''53# The text is text: what looked like markup is escaped or gone.54printf '%s' "$fig" | grep -q '<title id="diagram-[0-9a-f]\{8\}-title"></title><script>alert(.acc.)</script></title>' || fail "accTitle not escaped"55# Init directives don't reach the SVG (their CSS stays out of its tags; the56# label that says it is text), and raw SVG in the markdown is dropped.57if tags | grep -q 'display'; then fail "the diagram's CSS reached a tag"; fi58lacks "$p" 'evil\.example|onload|onerror|<rect width="9999"'