mirror of
https://github.com/safishamsi/graphify.git
synced 2026-09-12 16:45:58 +00:00
fix(export): close stored XSS + broken neighbor links in graph.html (#1838)
The HTML report's neighbor "focus" links dropped an unescaped JSON.stringify(nid) into a double-quoted inline onclick. The stringified value carries its own quotes, so the attribute was truncated on every node (links never worked), and a node id/label containing a double-quote broke out of the attribute and injected live event handlers. AST ids are [a-z0-9_]-safe, but ids/labels from documents or titles scraped via `graphify add <url>` are not, so a hostile source could plant an executable handler into a locally-opened report. Carry the id in an HTML-escaped data-nid attribute and dispatch via one delegated listener bound to document (survives the innerHTML rebuild that recreates #neighbors-list). Closes the injection and repairs the links. Reported by @edgestack-ai. Co-Authored-By: edgestack-ai <edgestack-ai@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
edgestack-ai
Claude Opus 4.8
parent
94d3099540
commit
98c7ec039a
@@ -175,7 +175,7 @@ function showInfo(nodeId) {{
|
||||
const neighborItems = neighborIds.map(nid => {{
|
||||
const nb = nodesDS.get(nid);
|
||||
const color = nb ? nb.color.background : '#555';
|
||||
return `<span class="neighbor-link" style="border-left-color:${{esc(color)}}" onclick="focusNode(${{JSON.stringify(nid)}})">${{esc(nb ? nb.label : nid)}}</span>`;
|
||||
return `<span class="neighbor-link" style="border-left-color:${{esc(color)}}" data-nid="${{esc(nid)}}">${{esc(nb ? nb.label : nid)}}</span>`;
|
||||
}}).join('');
|
||||
document.getElementById('info-content').innerHTML = `
|
||||
<div class="field"><b>${{esc(n.label)}}</b></div>
|
||||
@@ -193,6 +193,19 @@ function focusNode(nodeId) {{
|
||||
showInfo(nodeId);
|
||||
}}
|
||||
|
||||
// Neighbor links use a data attribute + one delegated listener rather than an
|
||||
// inline onclick. A node id/label sourced from a document or a scraped URL
|
||||
// (graphify add) can contain a double-quote; dropping the stringified id
|
||||
// unescaped into a quoted onclick both broke every link and allowed a hostile
|
||||
// source to inject an event handler into the local report (stored XSS, #1838).
|
||||
// esc() on data-nid keeps the value inside the attribute; the listener reads it
|
||||
// back verbatim. Bound to document so it survives the innerHTML rebuild that
|
||||
// recreates #neighbors-list on each showInfo().
|
||||
document.addEventListener('click', e => {{
|
||||
const el = e.target.closest('.neighbor-link');
|
||||
if (el && el.dataset.nid !== undefined) focusNode(el.dataset.nid);
|
||||
}});
|
||||
|
||||
// Track hovered node — hover detection is more reliable than click params
|
||||
let hoveredNodeId = null;
|
||||
network.on('hoverNode', params => {{
|
||||
|
||||
Reference in New Issue
Block a user