T09 · Insecure Skill Coding Practices
- Location
references/plugins/g6-plugin-tooltip.md:73- Finding
DOM XSS Through Unescaped Graph Data in Tooltip Content
- Content
View full analysis
{ const item = items[0]; if (!item) return ''; const { data } = item; return ``; }, ``` The second documented variant exposes every property of the graph data: ```javascript getContent: (event, items) => { const [item] = items; const d = item.data; return `${data.name || item.id}${data.age ? `年龄:${data.age}` : ''} ${data.dept ? `部门:${data.dept}` : ''} ${data.relation ? `关系:${data.relation}` : ''}`; }, ``` ### Technical Analysis The examples directly interpolate graph-record fields into strings returned by the G6 tooltip `getContent` callback. These strings are intended to be interpreted as HTML. No HTML escaping, contextual output encoding, sanitization, or trusted-data requirement is applied. Graph data commonly originates from APIs, imported files, databases, or user-generated records. Consequently, properties such as `name`, `dept`, `relation`, object keys, and object values must be treated as untrusted. An attacker-controlled value such as the following can introduce a ...[truncated 1618 chars]${d.name}
${Object.entries(d).map(([k, v]) => ` `).join('')}${k} ${v} - Remediation
View remediation
{ const item = items[0]; const container = document.createElement('div'); container.style.cssText = 'padding:8px 12px;min-width:120px'; const title = document.createElement('div'); title.style.cssText = 'font-weight:bold;margin-bottom:4px'; title.textContent = String(item?.data?.name ?? item?.id ?? ''); container.appendChild(title); for (const field of ['age', 'dept', 'relation']) { const value = item?.data?.[field]; if (value === undefined || value === null) continue; const row = document.createElement('div'); row.textContent = `${field}: ${String(value)}`; container.appendChild(row); } return container; }, ``` ]]>
