T09 · Insecure Skill Coding Practices
- Location
SKILL.md:87- Finding
Stored Script Injection Through Untrusted Task Data Embedded in the Dashboard
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 87-95 and 123-124
Vulnerability Type: Stored script injection in an HTML script context
Risk Level: HighVulnerable Code Snippet
markdown 1. Read unprocessed files from `inbox/`, or parse content pasted directly by the user. 2. Identify every task in the input. 3. For each task: - Infer the title, due date, category, and priority. - Create the corresponding Markdown file under `tasks/`. 4. Update `index.md` with the new tasks. 5. Update the embedded `TASKS_DATA` in `views/dashboard.html` by replacing the complete `var TASKS_DATA = ...;` line.The corresponding dashboard data format is specified at lines 249-262:
html <script> /* TASKS_DATA_START */ var TASKS_DATA = {"generated":"YYYY-MM-DD HH:mm","tasks":[...]}; /* TASKS_DATA_END */ </script>The Skill also requires the data to be written as single-line compressed JSON without requiring script-context escaping:
markdown TASKS_DATA must be written as compressed, single-line JSON.Technical Analysis
Task titles, notes, tags, and detail entries can originate from untrusted inbox files or content pasted by a user. The Skill instructs the agent to serialize these values into JSON and place the result directly inside an executable HTML
scriptelement.Standard JSON serialization protects JSON syntax but does not necessarily make the result safe for embedding in an HTML raw-text script context. In particular, an input containing a sequence such as:
html </script><script>ATTACKER_CODE</script>can cause the HTML parser to terminate the original
scriptelement before JavaScript parses the JSON. The following attacker-controlled element can then be interpreted as executable JavaScript.The
esc()helper specified at line 321 only escapes values during subsequent HTML rendering. It does not protect the initialTASKS_DATAsc ...[truncated 1563 chars]- Remediation
View remediation
Remediation Suggestions
-
Apply context-safe serialization before inserting JSON into HTML. At minimum, replace HTML-sensitive characters after JSON serialization:
javascript function safeJsonForHtml(value) { return JSON.stringify(value) .replace(/&/g, "\\u0026") .replace(/</g, "\\u003c") .replace(/>/g, "\\u003e") .replace(/\u2028/g, "\\u2028") .replace(/\u2029/g, "\\u2029"); }In an actual implementation, the replacements must target the literal characters
&,<, and>, rather than already encoded HTML entities. -
Prefer storing the data in a non-executable element:
html <script id="tasks-data" type="application/json"> SAFE_SERIALIZED_JSON </script>Then parse it using:
javascript var TASKS_DATA = JSON.parse( document.getElementById("tasks-data").textContent );Escaping the literal less-than character as
\u003cremains necessary because HTML parsing recognizes closingscripttags regardless of the script MIME type. -
Update the Skill instructions to explicitly require HTML script-context escaping for every generated
TASKS_DATAandARCHIVE_DATAvalue. -
Continue using
esc()or equivalent safe DOM APIs when rendering values. PrefertextContent,setAttribute, and element construction over concatenating untrusted strings intoinnerHTML. -
Add regression tests containing payloads such as closing
scripttags, HTML tags, quotes, backslashes, Unicode separators, and ampersands. Verify that opening the generated dashboard never creates attacker-supplied elements or executes code. -
Add a restrictive Content Security Policy. Where practical, move trusted interaction logic into a fixed local script and disallow arbitrary inline scripts. CSP should be treated as defense in depth rather than a replacement for safe serialization.
-
