T09 · Insecure Skill Coding Practices
- Location
scripts/verify.mjs:30- Finding
Automatic Execution of Attacker-Controlled Repository Commands
- Content
View full analysis
Vulnerability Details
File Location:
scripts/verify.mjs:30-32, with supporting execution flow atscripts/verify.mjs:83-87,scripts/verify.mjs:139-190, andscripts/verify.mjs:250-253; mandatory invocation is defined inSKILL.md:27-39
Vulnerability Type: Command injection and unsafe execution of untrusted project scripts
Risk Level: HighRelevant Code
Mandatory automatic invocation:
markdown 1. BEFORE changing code (any change touching logic, interfaces, or tests), run in the project root:node /scripts/verify.mjs snapshot
text 2. BEFORE reporting completion to the user, run in the project root:node /scripts/verify.mjs run
text Shell execution sink:
javascript function runCmd(cmd) { try { const out = execSync(cmd, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 600000, maxBuffer: 64 * 1024 * 1024 }); return { status: 'pass', output: out };Repository-controlled script loading and classification:
javascript if (has('package.json')) { let pkg = {}; try { pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')); } catch { notes.push('package.json 解析失败'); } const scripts = pkg.scripts || {};javascript for (const [key, cmd] of Object.entries(scripts)) { if (key === 'test') continue; if (/(^|[:._-])only$/.test(key.toLowerCase())) { notes.push(`脚本 "${key}" 疑似部分执行脚本(-only 后缀),依赖手动前置步骤,跳过`); continue; } const cat = classify(key, String(cmd)); if (cat && !isUnsafe(key, String(cmd))) candidates.push({ key, cat, cmd: String(cmd) }); } const hasComposite = candidates.some((c) => c.key === 'check'); const queued = new Set(); for (const c of candidates) { if (hasComposite && c.key !== 'check' && /^check($|:)/.test(c.key.toLowerCase())) continue; if (queued.has(c.cmd)) continue; queued.add(c.cmd); const dup = checks.filter((x) => x.name === c.cat).length; checks.push({ name: dup > 0 ? `$ ...[truncated 3771 chars]- Remediation
View remediation
Remediation Suggestions
-
Require informed confirmation for repository code execution
- Display the exact checks and command bodies that will run.
- Require explicit user approval before executing scripts from a newly opened or otherwise untrusted repository.
- Do not treat the general request to modify code as implicit authorization to execute arbitrary repository-defined commands.
-
Use process APIs without shell interpretation
- Replace shell command strings with
spawnSync()orexecFileSync()using an executable and argument array. - Set
shell: false. - For NPM scripts, pass the script name as a discrete argument, such as
spawnSync("npm", ["run", "--", key], options). - Validate script keys against a conservative allowlist even when argument-based process execution is used.
- Replace shell command strings with
-
Do not infer command safety from substring classification
- Treat classification only as discovery.
- Parse and reject command chaining, command substitution, redirection, shell pipelines, and unrelated secondary commands.
- Prefer known checker binaries invoked directly with fixed arguments rather than running arbitrary package scripts.
-
Sandbox verification
- Run repository checks in an isolated container or restricted worker.
- Mount only the target repository, preferably with read-only access except for an explicitly designated output directory.
- Remove unrelated credentials and environment variables.
- Disable network access unless a specific check requires it and the user approves it.
- Apply CPU, memory, process, and execution-time limits.
-
Use a review-first workflow
- List detected checks and report that they are untrusted until reviewed.
- Allow the user to approve checks individually.
- Preserve
UNVERIFIEDas the outcome when safe execution cannot be guaranteed rather than automatically running repository-controlled commands.
-
