T09 · Insecure Skill Coding Practices
- Location
index.js:140- Finding
Arbitrary Shell Command Execution Through Untrusted Smoke-Test Command
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 140-148
Vulnerability Type: OS command injection throughchild_process.exec
Risk Level: HighVulnerable Code
javascript if (extractionResult.smokeTestCommand) { try { console.error(`[ArXiv Skill Learning] Executing: ${extractionResult.smokeTestCommand}`); // Ensure we run in workspace root to resolve paths correctly const { stdout, stderr } = await execAsync(extractionResult.smokeTestCommand, { encoding: 'utf8', timeout: 60000, // Increased timeout to 60s cwd: WORKSPACE_ROOT });Technical Analysis
extractionResult.smokeTestCommandis produced by an external extractor after it processes remotely sourced paper content. The value is passed directly toexecAsync, which is a promisified version ofchild_process.exec.execinterprets its input through a system shell. Consequently, shell operators, command substitutions, redirections, pipelines, and additional commands embedded insmokeTestCommandwill be executed. The code applies no executable allowlist, argument validation, shell-metacharacter rejection, path containment check, sandbox, or privilege restriction.A compromised extractor, malicious dependency, or adversarial extraction result can therefore turn the smoke-test facility into an arbitrary command-execution primitive.
Attack Path
- An attacker influences the paper-derived extraction input or compromises the sibling
arxiv-skill-extractorcomponent. - The extractor returns a valid-looking result containing a
skillNameand a malicioussmokeTestCommand. - The learning workflow verifies only that
extractionResult.skillNameexists; it does not validate the command. - The command is supplied unchanged to
execAsync. - The operating-system shell interprets and executes the attacker's command from
WORKSPACE_ROOT. - The payload runs with the same opera ...[truncated 889 chars]
- An attacker influences the paper-derived extraction input or compromises the sibling
- Remediation
View remediation
Remediation Suggestions
- Do not accept an arbitrary shell command from the extractor. Define smoke tests as structured data containing a fixed test-runner identifier and a validated array of arguments.
- Replace
child_process.execwithexecFileorspawn, and explicitly setshell: false. - Allowlist permitted executables and test actions rather than attempting to sanitize arbitrary shell text.
- Resolve and validate all referenced paths. Require them to remain inside the generated skill directory using canonical-path containment checks.
- Reject shell metacharacters, redirections, command substitutions, unexpected environment assignments, and unsupported arguments as defense in depth.
- Run generated tests in an isolated, low-privilege sandbox or container with a read-only workspace, a dedicated temporary directory, strict resource limits, and no access to credentials.
- Disable network access during testing unless it is explicitly required and tightly restricted.
- Apply output-size limits in addition to the existing execution timeout.
- Treat the extractor and all paper-derived content as untrusted, and validate the entire extraction result against a strict schema before use.
