diff --git a/static/panels.js b/static/panels.js index 8ebf44d6..ca7e6733 100644 --- a/static/panels.js +++ b/static/panels.js @@ -5569,7 +5569,7 @@ async function loadProvidersPanel(){ list.appendChild(_buildProviderCard(p)); } }catch(e){ - list.innerHTML='
Failed to load providers: '+e.message+'
'; + list.innerHTML='
Failed to load providers: '+esc(e.message||String(e))+'
'; } } diff --git a/static/ui.js b/static/ui.js index 0c716cb8..f270909f 100644 --- a/static/ui.js +++ b/static/ui.js @@ -1206,7 +1206,7 @@ function renderModelDropdown(){ } } const badgeHtml=m.badge?`${esc(badgeLabel)}`:''; - row.innerHTML=`
${esc(modelName)}${badgeHtml}
${m.id}`; + row.innerHTML=`
${esc(modelName)}${badgeHtml}
${esc(m.id)}`; row.onclick=()=>selectModelFromDropdown(m.value); dd.appendChild(row); } @@ -1234,7 +1234,7 @@ function renderModelDropdown(){ const badgeHtml=m.badge?`${esc(m.badge.label||'Configured')}`:''; // Inline provider chip on every row that has a group (#1425) const providerChip=m.group?`${esc(m.group)}`:''; - row.innerHTML=`
${m.name}${badgeHtml}${providerChip}
${m.id}`; + row.innerHTML=`
${esc(m.name)}${badgeHtml}${providerChip}
${esc(m.id)}`; row.onclick=()=>selectModelFromDropdown(m.value); dd.appendChild(row); } diff --git a/tests/test_model_picker_escaping.py b/tests/test_model_picker_escaping.py new file mode 100644 index 00000000..76fcd44e --- /dev/null +++ b/tests/test_model_picker_escaping.py @@ -0,0 +1,20 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def test_model_picker_escapes_provider_supplied_model_labels(): + src = (ROOT / "static" / "ui.js").read_text() + + assert '${esc(m.id)}' in src + assert '${esc(m.name)}' in src + assert '${m.id}' not in src + assert '${m.name}' not in src + + +def test_providers_panel_escapes_load_error_text(): + src = (ROOT / "static" / "panels.js").read_text() + + assert "Failed to load providers: '+esc(e.message||String(e))+'" in src + assert "Failed to load providers: '+e.message+'" not in src