T09 · Insecure Skill Coding Practices
- Location
scripts/get-hot-trend.js:13- Finding
Shell Command Injection Through Unvalidated CLI Argument
- Content
View full analysis
Vulnerability Details
File Location:
scripts/get-hot-trend.js, lines 13-18 and 72-74
Vulnerability Type: OS command injection
Risk Level: HighVulnerable Code
js function getHotTrend(limit = 10) { try { const scriptPath = path.join(__dirname, 'douyin.js'); const output = execSync(`node "${scriptPath}" hot ${limit}`, { encoding: 'utf-8', cwd: path.dirname(scriptPath) }); return output;js async function main() { const limit = process.argv[2] || 10; console.log('开始获取抖音热榜...'); const hotTrendData = getHotTrend(limit);Technical Analysis
The
limitvalue originates directly fromprocess.argv[2]and is interpolated into a command string passed tochild_process.execSync. This API executes the supplied string through a system shell.The argument is neither converted to a number nor validated against an allowlist or numeric range. Consequently, shell metacharacters contained in the CLI argument are interpreted as command syntax rather than as part of the intended item limit.
Although the normal use case supplies a number such as
10, any user, scheduler, or integration capable of controlling this argument can append an arbitrary operating-system command.Attack Path
- An attacker obtains the ability to invoke
scripts/get-hot-trend.jsor influence the argument supplied by an automation system. - The attacker provides an argument containing shell syntax, such as
10; id. main()stores the complete string inlimit.getHotTrend()constructs a command equivalent to:
text node "/project/scripts/douyin.js" hot 10; idexecSyncpasses the string to the system shell.- The intended Node.js command runs, followed by the injected command.
- The injected process executes with the same operating-system identity and permissions as the Skill process.
Impact Assessment
Successful exploitation permits arbitrary local c ...[truncated 661 chars]
- An attacker obtains the ability to invoke
- Remediation
View remediation
Remediation Suggestions
- Replace shell-based
execSyncwithexecFileSyncorspawnSync, passing every argument separately:
js const { execFileSync } = require('child_process'); function getHotTrend(limit = 10) { const scriptPath = path.join(__dirname, 'douyin.js'); return execFileSync( process.execPath, [scriptPath, 'hot', String(limit)], { encoding: 'utf-8', cwd: path.dirname(scriptPath), timeout: 30_000 } ); }- Parse and validate the CLI value before using it:
js const requestedLimit = Number.parseInt(process.argv[2] ?? '10', 10); if (!Number.isInteger(requestedLimit) || requestedLimit < 1 || requestedLimit > 50) { throw new Error('Limit must be an integer between 1 and 50'); }- Do not attempt to make shell interpolation safe through partial escaping. Avoid invoking a shell entirely when executing a fixed program.
- Apply a timeout and output-size controls to prevent the child process from hanging or exhausting resources.
- Run the Skill under a dedicated, least-privileged operating-system account without access to unrelated files or credentials.
- Add tests using shell metacharacters to verify that malformed values are rejected and never interpreted by a shell.
- Replace shell-based
