fix(security): block npm_execpath injection from workspace .env [AI-assisted]#73262
Conversation
Greptile SummaryThis PR closes an Confidence Score: 5/5Safe to merge — the fix is correct, all-casing variants are handled, and tests are strict. All three mitigating layers are implemented correctly. Case normalization is consistent ( No files require special attention. Reviews (2): Last reviewed commit: "fix: address PR review feedback" | Re-trigger Greptile |
|
|
||
| loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true }); | ||
|
|
||
| expect(process.env.npm_execpath).toBeUndefined(); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
There was a problem hiding this comment.
Test only covers lowercase key variant
The new test writes npm_execpath=./evil/npm-cli.js (lowercase) and asserts process.env.npm_execpath is undefined — but doesn't verify that NPM_EXECPATH=./evil/npm-cli.js in a workspace .env is also blocked. The implementation does handle this correctly via shouldBlockWorkspaceDotEnvKey's key.toUpperCase() normalisation, so there's no actual bug, but a second test case for the uppercase spelling would close the coverage gap and keep the test suite honest.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/dotenv.test.ts
Line: 375-382
Comment:
**Test only covers lowercase key variant**
The new test writes `npm_execpath=./evil/npm-cli.js` (lowercase) and asserts `process.env.npm_execpath` is undefined — but doesn't verify that `NPM_EXECPATH=./evil/npm-cli.js` in a workspace `.env` is also blocked. The implementation does handle this correctly via `shouldBlockWorkspaceDotEnvKey`'s `key.toUpperCase()` normalisation, so there's no actual bug, but a second test case for the uppercase spelling would close the coverage gap and keep the test suite honest.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Addressed in 18104c52d0a7a531c9813517deeeffe9db3e62d7.
|
@greptile review |
|
Codex review: keeping this open for maintainer follow-up; there is still a little grit to resolve. Keep open. This PR is protected by both MEMBER author association and the Best possible solution: Keep this PR open for maintainer/security review. The best path is to land it or an equivalent patch that blocks What I checked:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against ba722fd1265a. |
|
Addressed in Quoted comment from @aisle-research-bot:
|
|
Addressed in Quoted comment from @clawsweeper:
|
🔒 Aisle Security Analysis✅ We scanned this PR and did not find any security vulnerabilities. Analyzed PR: #73262 at commit Last updated on: 2026-04-28T12:53:27Z |
…ssisted] (openclaw#73262) * fix: address issue * fix: finalize issue changes * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge
…ssisted] (openclaw#73262) * fix: address issue * fix: finalize issue changes * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge
…ssisted] (openclaw#73262) * fix: address issue * fix: finalize issue changes * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge
…ssisted] (openclaw#73262) * fix: address issue * fix: finalize issue changes * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge
26194 drift commits, 222 flagged (security/regression keywords). Notable: XSS fix (openclaw#83104), PATH injection (openclaw#73264), npm_execpath injection (openclaw#73262), implicit tool grant fix (openclaw#75055), payment credential redaction (openclaw#75230), heartbeat regression (openclaw#88970).
Summary
.envfiles could setnpm_execpathto an attacker-controlled local script; the bundled runtime dependency installer trusted this value when selecting the npm runner, enabling arbitrary JS execution onopenclawstartup..envthat redirectsnpm_execpath, causing OpenClaw to execute an attacker-supplied script as part of bundled runtime dep repair — no user interaction beyond opening the project required.npm_execpath(any casing) is now blocked at two independent layers: (1) added toBLOCKED_WORKSPACE_DOTENV_KEYSinsrc/infra/dotenv.tsso it is never loaded from workspace.env; (2) stripped from the install env increateBundledRuntimeDepsInstallEnvbefore spawning npm; (3)resolveBundledRuntimeDepsNpmRunnerno longer readsnpm_execpathat all — runner selection is now purely Node-adjacent path resolution..envbehavior is unaffected.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
resolveBundledRuntimeDepsNpmRunnerreadenv.npm_execpathand, after a weak path-pattern check (isNpmCliPath), placed it first in the npm-cli candidate list. An attacker could satisfy the check by naming their filenpm-cli.js.npm_execpathwas not on the workspace.envblocklist, and no stripping occurred before the env was passed to the subprocess.npm_execpathis set by npm itself in lifecycle scripts and CI runners, so the original code was trying to reuse it — but that trust is inappropriate for attacker-controlled working directories.Regression Test Plan (if applicable)
src/plugins/bundled-runtime-deps.test.ts,src/infra/dotenv.test.tsnpm_execpath(andNPM_EXECPATH) is never used as the npm runner and is absent from the spawn env; workspace.envsettingnpm_execpathis blocked at load time.createBundledRuntimeDepsInstallEnvuses.toEqualto assert neither lowercase nor uppercase form appears in output; integration test forinstallBundledRuntimeDepsverifies the spawn env does not containnpm_execpath; runner tests confirm the attacker path is never selected even whenexistsSyncreturns true for it.User-visible / Behavior Changes
None.
npm_execpathwas an internal implementation detail; no documented behavior changes.Diagram (if applicable)
Security Impact (required)
npm_execpathcan no longer influence which npm CLI is executed during bundled runtime dep installation.npm_execpathto point to npm (e.g. custom Node installs with npm not in the standard relative location) will now fall through to the Node-adjacent path candidates and then the systemnpmfallback. This is the correct behavior;npm_execpathredirection from untrusted working directories is the vulnerability being closed.Repro + Verification
Environment
Steps
npm_execpath=/proc/self/cwd/evil/npm-cli.jsin workspace.env; trigger bundled runtime dep install; attacker script executes.npm_execpathis blocked at.envload; even if present in env via another vector, stripped before spawn; runner ignores it entirely.Expected
npm_execpathis never used as the npm runner path.Actual
Evidence
bundled-runtime-deps.test.tsanddotenv.test.tscover the attack scenarios and pass with the fix applied.Human Verification (required)
.toEqual), runner ignoring attacker path on Linux and Windows, and spawn env absence assertion.NPM_EXECPATHstripping, WindowsexistsSync-positive attacker path still rejected, non-Windows fallback PATH env does not reintroduce the key.Review Conversations
Compatibility / Migration
Risks and Mitigations
../lib/node_modules/npm/bin/npm-cli.jsnornode_modules/npm/bin/npm-cli.js(relative tonode) exist may fall through to thenpmshell command instead of the bundled npm-cli.js. This was already the pre-existing fallback behavior before thenpm_execpathpath was added.command: "npm", PATH-based) is the same behavior as beforenpm_execpathsupport was introduced and is safe for trusted system npm installs.