T09 · Insecure Skill Coding Practices
- Location
mg-wizard.cjs:993- Finding
Shell Command Injection Through Unvalidated Interactive Input
- Content
View full analysis
/dev/null | grep -i error || echo '暂无错误日志'`, { stdio: 'inherit' } ); const ssCheck = execSync( `ss -tlnp 2>/dev/null | grep ":${gatewayPort} " || true`, { encoding: 'utf8' } ); const netstatCheck = execSync( `netstat -tlnp 2>/dev/null | grep ":${gatewayPort} " || true`, { encoding: 'utf8' } ); ``` The pairing code and gateway name are also passed through a shell: ```js const pairingCode = await question('配对码(6 位数字): '); if (pairingCode && pairingCode.length >= 4) { console.log('\n正在提交配对码...'); try { const result = execSync( `openclaw pairing ${pairingCode.trim()} --agent ${gatewayName}`, { encoding: 'utf8', stdio: 'pipe' } ); log.success('配对成功!'); console.log(result); } catch (e) { log.warn('配对命令执行失败,请手动配对'); log.warn(`手动配对:openclaw pairing ${pairingCode.trim()} --agent ${gatewayName}`); } } ``` ### Technical Analysis `execSync()` invokes the command through a shell when supplied with a command string. The wizard inserts `gatewayName`, `gatewayPort`, and `pairingCode` directly into these command s ...[truncated 1766 chars]- Remediation
View remediation
65535) { throw new Error('Invalid gateway port'); } if (!/^\d{6}$/.test(pairingCode.trim())) { throw new Error('Invalid pairing code'); } ``` 3. Never concatenate interactive input into shell commands, even after generic escaping. 4. Pass log paths directly to filesystem APIs instead of invoking `tail` through a shell. 5. Add automated tests containing shell metacharacters, path separators, whitespace, and newlines. ]]>
