T09 · Insecure Skill Coding Practices
- Location
SKILL.md:24- Finding
JavaScript Code Injection Through Unvalidated Water Intake Input
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 24-27
Vulnerability Type: User-controlled input interpolated into executable JavaScript
Risk Level: HighVulnerable Code
markdown When user says "uống X cốc" or "uống nước X cốc": ```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')"Replace
CUPSwith number from user input.text ### Technical Analysis The Skill directs the agent to replace the `CUPS` placeholder with a value extracted from user input. The value is embedded directly into source code supplied to `node -e`, without strict numeric parsing, range validation, escaping, or separation through process arguments. If the agent accepts a crafted value rather than a valid numeric literal, the value could terminate or alter the intended JavaScript expression and inject additional JavaScript statements. Depending on shell metacharacters and quoting, unsafe interpolation may also affect the surrounding shell command. The vulnerability violates the boundary between data and executable code: user-provided data becomes part of dynamically constructed JavaScript source. ### Attack Path 1. An attacker submits a water-tracking request containing a crafted value in place of the expected cup count. 2. The agent extracts that value and substitutes it directly for `CUPS`. 3. The resulting text becomes part of the `node -e` JavaScript program. 4. When the command is executed, the injected JavaScript runs with the same operating-system privileges as the agent process. 5. The injected code could access or modify files available to that process or invoke further local commands through Node.js APIs. ### Impact Assessment Successful exploitation could provide arbitr ...[truncated 579 chars]- Remediation
View remediation
Remediation Suggestions
- Never insert the user-provided cup count into JavaScript source code.
- Parse the value using a fixed program and pass it as a separate process argument, for example through
process.argv. - Convert the argument with
Number()and reject it unlessNumber.isFinite()succeeds. - Enforce an appropriate numeric range, such as a positive value with a reasonable maximum.
- Reject unexpected characters instead of attempting to escape executable input.
- Pass
{baseDir}as a separately validated argument rather than interpolating it into executable source. - Consider replacing the inline
node -ecommand with a fixed, reviewed script that treats all external values strictly as data. - Write updates atomically and apply restrictive permissions to the health-data file where supported.
A safer fixed script should follow this pattern:
javascript const cups = Number(process.argv[2]); if (!Number.isFinite(cups) || cups <= 0 || cups > 100) { throw new Error('Invalid cup count'); } data.water.push({ time: new Date().toISOString(), cups });
