Found during review of #456. Pre-existing on main.
The inline search script in templates/base.html (server mode) renders results with ${recipe.path} and ${recipe.name} inside an innerHTML template literal without escaping. static/js/search.js (static mode) does escape via escapeHtml. A recipe name containing < breaks the row, and a name with markup is the stored-XSS shape if recipes are ever imported from the web.
Fix: reuse the same escaping helper in the inline script, or move server-mode rendering into search.js.
Found during review of #456. Pre-existing on main.
The inline search script in
templates/base.html(server mode) renders results with${recipe.path}and${recipe.name}inside aninnerHTMLtemplate literal without escaping.static/js/search.js(static mode) does escape viaescapeHtml. A recipe name containing<breaks the row, and a name with markup is the stored-XSS shape if recipes are ever imported from the web.Fix: reuse the same escaping helper in the inline script, or move server-mode rendering into
search.js.