T09 · Insecure Skill Coding Practices
- Location
canvas-inject.py:18- Finding
JavaScript Injection Through Incomplete Template-Literal Escaping
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Canvas app skill is mostly purpose-aligned, but it should be reviewed because its scripts can expose local folders, kill unrelated local processes, and inject JavaScript into Canvas without strong scoping.
Install only if you are comfortable with a skill that starts local web servers, injects JavaScript into Canvas, and lets Canvas apps send messages back to the agent. Use it only with trusted app content and trusted data, avoid arbitrary app names or ports, and review the scripts before allowing process cleanup or serving local directories.
canvas-inject.py:18JavaScript Injection Through Incomplete Template-Literal Escaping
templates/dashboard/index.html:98DOM-Based Cross-Site Scripting in Dashboard List Rendering
templates/tracker/index.html:126DOM-Based Cross-Site Scripting in Tracker Item Rendering
open-app.sh:23Directory Traversal Can Expose Arbitrary Directories Over the Network
close-app.sh:10Predictable and Untrusted PID Files Permit Process Termination and File Clobbering
open-app.sh:17Unconditional Force-Termination of Unrelated Port Owners
The skill is presented as a UI/app-platform helper, but it also instructs arbitrary JavaScript injection into a live Canvas target using eval/document.write and direct node manipulation. That mismatch is dangerous because it hides powerful code-execution behavior behind an innocuous description, making abuse or unsafe invocation more likely.
The README explicitly promotes 'Live data injection via JavaScript eval' and 'Two-way communication' where apps send commands back to the agent, but it provides no warning about trust boundaries, input validation, or the system-impacting nature of those capabilities. In this skill's context, that omission is dangerous because combining eval-based injection with agent command callbacks can enable code execution, prompt/command injection, or unintended agent actions from app-controlled content.
The README advertises highly generic trigger phrases such as 'Open business dashboard' and 'Show my stats on canvas' that are likely to collide with ordinary user requests. In an agentic environment, broad activation phrases can cause the skill to run unintentionally, which is especially risky here because the skill can launch local content, inject JavaScript, and receive commands back from the app.
The skill documents shell-capable operations such as starting HTTP servers, killing processes, and navigating/evaluating code on Canvas, but it declares no explicit tool scope or permissions boundary. This increases the risk of unintended command execution because users and the platform cannot clearly constrain what the skill is allowed to do.
Trigger phrases like 'Open [app]', 'Update [element]', and 'Show [data] on canvas' are broad and overlap with normal conversational requests, increasing the chance the skill activates when the user did not intend privileged Canvas or shell actions. Because this skill can start servers and inject code into a target UI, accidental activation carries meaningful security risk.
The documented command lsof -ti:$PORT | xargs kill -9 forcibly terminates any process bound to the port without validating ownership or warning the user. This can disrupt unrelated local services and cause data loss or denial of service if used on a shared or important port.
This helper is explicitly designed to bypass normal Canvas loading restrictions by opening about:blank and then using an eval action to execute JavaScript that calls document.write() with attacker-controlled HTML. If html_content is influenced by untrusted input, this becomes arbitrary script/HTML injection in the Canvas target, enabling XSS-like behavior, credential theft, UI spoofing, or execution of privileged in-canvas actions.
The function is documented as HTML injection, but it actually returns an eval action that executes JavaScript in the target context. That mismatch is dangerous because downstream users may believe they are only rendering markup, while in reality they are enabling code execution with any scripts or event handlers embedded in the supplied HTML.
The script reads a PID from a predictable file in /tmp and then unconditionally sends SIGKILL to that PID before deleting the file. If the PID file is stale, tampered with, or points to a reused PID, the script can terminate the wrong process, creating a local denial-of-service risk and making recovery/debugging harder because SIGKILL bypasses graceful shutdown.
The script unconditionally force-kills every process bound to the requested port using lsof ... | xargs kill -9, with no validation, confirmation, or ownership check. Because the port is user-controlled, this can terminate unrelated services on the host, causing denial of service or data loss if a critical process is using that port.
The page sends user interaction data to an external agent via the custom openclaw://agent URI whenever a tracker item is toggled, and the add button also triggers an agent message. This creates an undisclosed data flow from local UI actions to another component, potentially exposing habit names and completion status without clear consent or visibility to the user.
The document sets lang="en", which hard-codes English as the page language. Under the stated policy, forcing a specific language without user opt-in or clear justification is a natural-language locale policy violation.
No suspicious patterns detected.