An embed’s <title> treats the timeline title as a replacement pattern
Free, open-source timeline editor for exact dates at any scale.
Brought to you by:
athanclark
Originally created by: athanclark
Embed <title>: the timeline title is used as a String.replace replacement pattern
platform/app/embed/[id]/route.js:39-42.html.replace(/<title>…<\/title>/, \<title>${escape(title)}…`)<code>passes a string, so</code>$'<code>, `` $</code> <code>` and</code>$&<code>in a timeline's title are expanded.</code>escape()<code>does not escape</code>$<code>. A title of</code>x $' y<code>copies the rest of dist/index.html (75 KB) into the</code><title><code>element (title.mjs: the document grows from 75,254 to 149,160 bytes). Inside the RCDATA</code><title><code>this is inert text, because dist/index.html contains only one</code></title>. If a later build adds an SVG<title>` after the head, duplicated trusted markup (including the app's script tag) would be parsed twice and break the embed. No attacker markup is ever injected.</li>
<li><strong>Suggested fix:</strong> pass a replacer function: <code>.replace(re, () => …)</code>. editor-html.js already does this for the user-controlled parts.</li>
<li><strong>Confidence:</strong> confirmed.</li>
</ul>
<hr>
<p>From the security review of 2026-11-06 (commit 6776c44), finding I-3: hardening or information, filed publicly because it describes no way in. The exploitable findings are private security advisories.</p>
<p>🤖 Generated with <a href="https://claude.com/claude-code">Claude Code</a></p>
<p><a href="https://claude.ai/code/session_011fFY8eruEi1xAkkMBni13B">https://claude.ai/code/session_011fFY8eruEi1xAkkMBni13B</a></p></title>
Ticket changed by: athanclark