T09 · Insecure Skill Coding Practices
Warning
- Location
- examples/full-delivery-example.md:337
- Finding
- Unsafe HTML Rendering Enables DOM-Based Cross-Site Scripting in the Full Delivery Example<![CDATA[ ## Vulnerability Details **File Location**: `examples/full-delivery-example.md:337-414` **Vulnerability Type**: DOM-based cross-site scripting through unsanitized `innerHTML` assignments **Risk Level**: Medium ### Vulnerable Code ```javascript function renderPage(data) { document.getElementById('tab-tasks').innerHTML = renderTasksTab(data.progressRoute, data.tasks, data.lottery); document.getElementById('tab-checkpoints').innerHTML = renderCheckpoints(data.checkpointRewards); document.getElementById('tab-benefits').innerHTML = renderBenefitsTab(data.rewardPool, data.rules); } function renderTasksTab(route, tasks, lottery) { return '<div class="panel-title"><h2>闯关进度</h2><span>' + route.tip + '</span></div><div class="route-track">' + route.steps.map(function (item) { return '<div class="route-step' + (item.done ? ' is-done' : '') + '">' + '<b>' + item.label + '</b><span>' + item.note + '</span>' + '</div>'; }).join('') + '</div><div class="task-stack">' + tasks.map(function (task) { return '<article class="task-item">' + '<div><p class="task-type">' + task.type + '</p><h3>' + task.title + '</h3><p>' + task.benefit + '</p></div>' + '<button class="js-task-action" data-id="' + task.id + '">' + task.ctaText + '</button>' + '</article>'; }).join('') + '</div>' + '<div class="draw-stage"><strong>' + lottery.chanceText + '</strong><button class="draw-button js-start-draw">' + lottery.ctaText + '</button></div>'; } function renderCheckpoints(checkpoints) { return checkpoints.map(function (item) { return '<article class="checkpoint-card">' + '<span class="checkpoint-index">' + item.index + '</span>' + '<strong>' + item.title + '</strong>' + '<p>' + item.desc + '</p>' + '<span class="checkpoint-status">' + item.statusText + '</span>' + '</article>'; }).join(''); } function renderBenefitsTab(rewardPool, rules) { return '<div class="panel-title"><h2>奖池展示</h2></ ...[truncated 2976 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Replace HTML-string concatenation with DOM construction APIs such as `document.createElement()`, `append()`, and `replaceChildren()`. - Assign untrusted display values through `textContent`. - Assign identifiers through `element.dataset.id` rather than interpolating them into HTML attributes. - If rich HTML is an explicit requirement, sanitize it with a maintained allowlist-based sanitizer before insertion. - Validate campaign-data objects against a strict schema, including expected types, maximum lengths, and permitted identifier formats. - Add a security rule to `SKILL.md` requiring generated delivery code to treat screenshot-derived, user-supplied, and API-supplied text as untrusted. - Add tests containing HTML metacharacters and representative XSS payloads to confirm that generated pages render them as text. - Deploy a restrictive Content Security Policy as defense in depth, while not treating it as a replacement for safe DOM rendering. ]]>
