Back to skill

Security audit

healthcheck

Security checks for vulnerabilities and agentic risk

Overview

The skill is a simple local health tracker, but its command templates can turn user-supplied numbers into executable JavaScript.

Review this skill before installing. It stores water and sleep records locally and may update or delete that history. The main issue is that its command examples should be rewritten to pass cup counts as validated arguments instead of inserting them into JavaScript source.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:25
Finding
User-Controlled Water Quantity Injected into Executable JavaScript## Vulnerability Details **File Location**: `SKILL.md`, line 25 **Vulnerability Type**: JavaScript code injection through unsafe source-code substitution **Risk Level**: High ### Vulnerable Code ```bash node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d={water:[],sleep:[]};try{d=JSON.parse(fs.readFileSync(f))}catch(e){}d.water.push({time:new Date().toISOString(),cups:CUPS});fs.writeFileSync(f,JSON.stringify(d));console.log('Da ghi: '+CUPS+' coc')" ``` The accompanying instruction directs the agent to replace `CUPS` with a number obtained from user input. It does not require strict numeric parsing, range validation, or safe argument passing. ### Technical Analysis `CUPS` is embedded directly into JavaScript source passed to `node -e`. If an agent substitutes the raw or insufficiently validated user-controlled value, an attacker can terminate the intended expression and append arbitrary JavaScript. For example, a value shaped like the following can escape the intended `cups` property expression: ```javascript 0});require('child_process').execSync('id');/* ``` After substitution, Node.js evaluates both the intended record operation and the injected statement. The trailing comment can suppress the remaining generated source. Because `require` is available, injected code can access Node.js filesystem, process, networking, and child-process capabilities. This issue does not require a third-party dependency or a remote payload. It results from constructing executable source code with a user-derived value. ### Attack Path 1. An attacker submits a water-tracking request containing a crafted value instead of a normal cup count. 2. The agent follows the skill instruction and substitutes that value for `CUPS` without strict numeric validation. 3. The resulting command is supplied to `node -e`. 4. Node.js parses the crafted value as executable source rather than merely as health-record data. 5. Th ...[truncated 600 chars]
Remediation
## Remediation Suggestions Do not insert user-controlled values into JavaScript source. Keep the script fixed and pass the quantity as a separate argument or through a structured input channel. Parse and validate it before use. A hardened implementation should: 1. Pass the value as a command-line argument rather than interpolating it into the `node -e` program. 2. Convert it with `Number(...)`. 3. Reject values for which `Number.isFinite(...)` is false. 4. Enforce an appropriate range and, if required by the data model, integer-only input. 5. Avoid invoking a shell where a direct Node.js process call or standalone script is available. 6. Report invalid input without modifying the JSON file. Example validation logic: ```javascript const cups = Number(process.argv[1]); if (!Number.isFinite(cups) || !Number.isInteger(cups) || cups < 0 || cups > 100) { throw new Error('Invalid cup count'); } ``` Prefer placing this fixed logic in a reviewed script and invoking it with an argument array so input is treated exclusively as data.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:62
Finding
User-Controlled Updated Quantity Injected into Executable JavaScript## Vulnerability Details **File Location**: `SKILL.md`, line 62 **Vulnerability Type**: JavaScript code injection through unsafe source-code substitution **Risk Level**: High ### Vulnerable Code ```bash node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d=JSON.parse(fs.readFileSync(f));d.water[d.water.length-1].cups=NEW_CUPS;fs.writeFileSync(f,JSON.stringify(d));console.log('Updated')" ``` `NEW_CUPS` is used as an executable JavaScript expression rather than being passed as data. The skill provides no mandatory numeric parsing, syntax restrictions, or range checks before substitution. ### Technical Analysis A crafted replacement can terminate the assignment and introduce another JavaScript statement. For example: ```javascript 0;require('child_process').execSync('id');/* ``` If this value is substituted directly for `NEW_CUPS`, the resulting `node -e` program assigns zero, executes the injected command, and comments out the remainder. Other Node.js APIs could similarly be invoked to interact with files, processes, or the network. Although the operation is presented as an update to a JSON record, the unsafe boundary is the generated `node -e` source itself. JSON serialization does not mitigate the vulnerability because injection occurs before serialization. ### Attack Path 1. An attacker asks the agent to update the last water record using a crafted replacement quantity. 2. The agent substitutes the supplied content into the `NEW_CUPS` placeholder. 3. The generated source is executed through `node -e`. 4. The crafted expression escapes the intended assignment and runs attacker-selected JavaScript. 5. Any resulting filesystem or process operations execute with the agent process's existing permissions. ### Impact Assessment Exploitation can provide arbitrary local code execution within the security context of the skill runner. Accessible files and records may be read, altered, or delete ...[truncated 258 chars]
Remediation
## Remediation Suggestions Replace source-code substitution with a fixed program that accepts the updated value as data. Parse and validate the argument before reading or modifying the record. Recommended controls include: 1. Convert the supplied value using `Number(...)` and require `Number.isFinite(...)`. 2. Enforce integer and reasonable minimum/maximum constraints where appropriate. 3. Reject malformed input before opening or writing `health-data.json`. 4. Pass arguments through an argument array rather than constructing a shell command. 5. Store the implementation in a static, reviewed script instead of dynamically generating JavaScript. 6. Validate that `d.water` is an array and contains an entry before attempting the update. 7. Write updates atomically to reduce corruption risk if execution is interrupted. Example fixed-script validation: ```javascript const newCups = Number(process.argv[2]); if (!Number.isFinite(newCups) || !Number.isInteger(newCups) || newCups < 0 || newCups > 100) { throw new Error('Invalid updated cup count'); } ``` The validated `newCups` variable should then be assigned directly to the parsed data structure without ever becoming part of executable source.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill performs persistent local file creation, modification, and deletion of health-related records without any user-facing warning, confirmation flow, or documentation about data persistence. This creates a privacy and integrity risk because users may unknowingly cause storage of sensitive behavioral data or destructive updates to prior records.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The natural-language instructions specify activation only through Vietnamese phrases such as "uống X cốc" and similar commands, with no indication that other languages are accepted or that the locale restriction is intentional and documented. Under SQP-3, forcing a specific language without user opt-in is a natural-language policy violation.

Static analysis

No suspicious patterns detected.