Skip to content

explainers-ui.js's client-side markdown renderer double-escapes '&' in link URLs, same bug as build_explainers.py #474

Description

@yakew7

Where: assets/explainers-ui.js's inlineMarkdown (lines 33-45) - escapeHtml(text) runs on the whole raw text first, then escapeHtml(resolved) runs again on the URL extracted from inside it. The same underlying bug as the companion issue in scripts/build_explainers.py, but in the site's client-side renderer - a genuinely separate, independently-reachable code path.

The gap: this function is real, live code: index.html loads explainers-ui.js, whose renderDetailPage() fetches an explainer's raw .md file client-side (fetch(\explainers/${entry.slug}.md`)) and renders it via renderMarkdown()->inlineMarkdown(), independently of the pre-built static HTML pages scripts/build_explainers.py` generates server-side.

Repro:

function escapeHtml(value) {
  return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}
function inlineMarkdown(text) {
  const escaped = escapeHtml(text);
  return escaped.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) =>
    `<a href="${escapeHtml(url.trim())}">${label}</a>`);
}
console.log(inlineMarkdown('[cite](https://www.wicourts.gov/x.pdf?content=pdf&seqNo=188417)'));
// <a href="https://www.wicourts.gov/x.pdf?content=pdf&amp;amp;seqNo=188417">cite</a>

Same double-escaping as the server-side generator - confirmed with the exact function bodies from assets/explainers-ui.js.

Why it matters: any explainer with an & in a link URL - including the State v. Loomis citation in automation-bias.md already confirmed broken in the companion server-side issue - breaks the same way if rendered through this client-side path, independently of whether the static HTML generator is ever fixed.

Suggested fix: apply the same fix as the companion scripts/build_explainers.py issue here too - extract the raw URL from unescaped text before escaping the surrounding line, or restructure inlineMarkdown so the URL substring is only ever escaped once.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions