Skip to content

fix(cli): prevent command injection via ZX_* variables loaded from --env#1447

Open
l3tchupkt wants to merge 1 commit intogoogle:mainfrom
l3tchupkt:fix-env-file-control-plane-injection
Open

fix(cli): prevent command injection via ZX_* variables loaded from --env#1447
l3tchupkt wants to merge 1 commit intogoogle:mainfrom
l3tchupkt:fix-env-file-control-plane-injection

Conversation

@l3tchupkt
Copy link
Copy Markdown

Reported-by: LAKSHMIKANTHAN K (letchupkt)
CWE: CWE-78 (Command Injection)

Summary

This PR fixes a command injection vulnerability in the zx CLI caused by unsafe handling of environment variables loaded via the --env option.

Previously, .env files loaded through dotenv.config() were merged directly into process.env, after which resolveDefaults() imported ZX_* variables into runtime execution settings. This allowed attacker-controlled .env files to influence execution parameters such as ZX_PREFIX, ZX_POSTFIX, and ZX_SHELL.

As a result, untrusted configuration files could inject arbitrary shell commands into otherwise safe scripts.

Relevant technical choices

  • Enforced separation between configuration data and execution control parameters

  • Prevented resolveDefaults() from importing ZX_* variables originating from .env files

  • Introduced filtering/blocking of sensitive execution keys when loaded via --env, including:

    • ZX_PREFIX
    • ZX_POSTFIX
    • ZX_SHELL
    • ZX_CWD
    • ZX_PREFER_LOCAL
  • Ensured that only trusted sources (CLI flags or direct environment) can control execution behavior

  • Maintained backward compatibility for standard .env usage while removing unsafe control-plane influence

Impact

Prevents command injection through malicious .env files.

This mitigates risks such as:

  • Arbitrary command execution via ZX_PREFIX / ZX_POSTFIX
  • Supply-chain attacks through modified configuration files
  • Silent compromise of trusted scripts before execution

Usage demo

import {$} from 'zx'
  • Setup Set the latest Node.js LTS version.
  • Build: I’ve run npm build before committing and verified the bundle updates correctly.
  • Tests: I’ve run test and confirmed all tests succeed. Added tests to cover my changes if needed.
  • Docs: I’ve added or updated relevant documentation as needed.
  • Sign Commits have verified signatures and follow conventional commits spec
  • CoC: My changes follow the project’s coding guidelines and Code of Conduct.
  • Review: This PR represents original work and is not solely generated by AI tools.

@google-cla
Copy link
Copy Markdown

google-cla bot commented Mar 30, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

loading a .env file via --env merges its contents into process.env, which
resolveDefaults() then blindly promotes into live execution settings.  An
attacker who can modify the .env file (supply-chain PR, compromised dep) can
set ZX_PREFIX/ZX_POSTFIX/ZX_SHELL to arbitrary shell code that runs for every
 call in an otherwise-trusted script.

Fix: snapshot ZX_* keys present in process.env before dotenv.config() runs,
then purge any ZX_* key introduced by the file before resolveDefaults() sees
the environment.  Legitimate ZX_* variables set by the operator (e.g. from the
shell that launched zx) are preserved; only file-injected ones are stripped.

Reported-by: LAKSHMIKANTHAN K (letchupkt)
CWE: CWE-94 / CWE-77 (Command Injection)
@l3tchupkt l3tchupkt force-pushed the fix-env-file-control-plane-injection branch from 1f7badb to ade6207 Compare March 30, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant