T09 · Insecure Skill Coding Practices
- Location
scripts/web_dashboard.py:202- Finding
Stored Script Injection in the Local Web Dashboard
- Content
View full analysis
Vulnerability Details
File Location:
scripts/web_dashboard.py, lines 202 and 243–258
Vulnerability Type: Stored script injection in generated HTML
Risk Level: MediumVulnerable Code:
python const node = {json.dumps({nid: n.get('output_data', {}) for nid, n in nodes.items()}, ensure_ascii=False)}[d.name];The injected JavaScript runs in the same page as the approval functions:
javascript function approvePipeline() { fetch('/api/approve', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Local-Token': localStorage.getItem('token') || '' }, body: JSON.stringify({ action: 'approve' }) }).then(r => r.json()).then(d => alert(d.message || JSON.stringify(d))); } function rejectPipeline() { fetch('/api/approve', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Local-Token': localStorage.getItem('token') || '' }, body: JSON.stringify({ action: 'reject' }) }).then(r => r.json()).then(d => alert(d.message || JSON.stringify(d))); }Technical Analysis
The dashboard serializes pipeline node
output_datawithjson.dumps()and inserts the result directly into an executable HTML<script>element. JSON string encoding does not make data safe for an HTML script context because it does not necessarily neutralize the HTML parser’s</script>closing sequence.Consequently, an output value containing a payload such as:
html </script><script>/* attacker-controlled JavaScript */</script>can terminate the intended script block and introduce a new executable script element. This is a stored injection because the payload is first persisted in pipeline state and executes later when the dashboard detail page renders that state.
Pipeline output can include content collected by automated nodes from websites or other external sources. Such content crosses from an untrusted data context into the trusted localhost dashboard origin wi ...[truncated 1822 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not interpolate serialized pipeline data directly into executable JavaScript source.
- Prefer serving pipeline details through a JSON endpoint and fetching them from the page. Parse the response as data and render values with safe DOM APIs such as
textContent. - If JSON must be embedded in HTML, place it in a non-executable element such as:
html <script id="pipeline-data" type="application/json">...</script>Before embedding, escape HTML-significant characters, especially
<, as Unicode escapes such as\u003c. Also escape>,&, U+2028, and U+2029 where appropriate. 4. Apply context-specific HTML escaping topipeline_name, node identifiers, approval-node labels, and every other value inserted into HTML markup. 5. Add a restrictive Content Security Policy that disallows inline and untrusted scripts. Use nonces or hashes for required local scripts. 6. Add regression tests using payloads containing</script>, HTML elements, quotes, ampersands, and Unicode line separators. Verify that they remain inert text in the generated page. 7. Avoid storing the approval token inlocalStorage. Prefer an HttpOnly, SameSite cookie or another mechanism unavailable to injected JavaScript, while retaining server-side authorization checks.
