Skip to content

chore(deps): update dependency zx to v8.8.5 [security]#13029

Merged
renovate[bot] merged 1 commit into
mainfrom
renovate/npm-zx-vulnerability
Apr 29, 2026
Merged

chore(deps): update dependency zx to v8.8.5 [security]#13029
renovate[bot] merged 1 commit into
mainfrom
renovate/npm-zx-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate Bot commented Nov 21, 2025

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
zx (source) 8.3.08.8.5 age adoption passing confidence

zx Uses Incorrectly-Resolved Name or Reference

CVE-2025-13437 / GHSA-w87r-vg9q-crqm

More information

Details

When zx is invoked with --prefer-local=, the CLI creates a symlink named ./node_modules pointing to /node_modules. Due to a logic error in src/cli.ts (linkNodeModules / cleanup), the function returns the target path instead of the alias (symlink path). The later cleanup routine removes what it received, which deletes the target directory itself. Result: zx can delete an external /node_modules outside the current working directory.

Severity

  • CVSS Score: 5.6 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:H/VA:H/SC:N/SI:H/SA:H/E:U

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

google/zx (zx)

v8.8.5: — Temporary Reservoir

Compare Source

This release fixes the issue, when zx flushes external node_modules on linking #​1348 #​1349 #​1355

Also globby@15.0.0 arrives here.

v8.8.4: — Flange Coupling

Compare Source

It's time. This release updates zx internals to make the ps API and related methods ProcessPromise.kill(), kill() work on Windows systems without wmic.
#​1344 webpod/ps#15

  1. WMIC will be missing in Windows 11 25H2 (kernel >= 26000)
  2. The windows-latest label in GitHub Actions will migrate from Windows Server 2022 to Windows Server 2025 beginning September 2, 2025 and finishing by September 30, 2025.

https://github.blog/changelog/2025-07-31-github-actions-new-apis-and-windows-latest-migration-notice/#windows-latest-image-label-migration

v8.8.3: — Sealing Gasket

Compare Source

Continues #​1339 to prevent injections via Proxy input or custom toString() manipulations.

v8.8.2: — Leaking Valve

Compare Source

Fixes potential cmd injection via kill() method for Windows platform. #​1337 #​1339. Affects the versions range 8.7.1...8.8.1.

v8.8.1: — Turbo Flush

Compare Source

We keep improving the projects internal infra to bring more stability, safety and performance for artifacts.

Featfixes
  • Applied flags filtration for CLI-driven deps install #​1308
  • Added kill() event logging #​1312
  • Set SIGTERM as kill() fallback signal #​1313
  • Allowed stdio() arg be an array #​1311
const p = $({halt: true})`cmd`
p.stdio([stream, 'ignore', 'pipe'])
Enhancements

v8.8.0: — Pressure Tested

Compare Source

This release enhances the coherence between the ProcessPromise and the Streams API, eliminating the need for certain script-level workarounds.

✨ New Features
unpipe() — Selectively stop piping

You can now call .unpipe() to stop data transfer from a source to a destination without closing any of the pair. #​1302

const p1 = $`echo foo && sleep 0.1 && echo bar && sleep 0.1 && echo baz && sleep 0.1 && echo qux`
const p2 = $`echo 1 && sleep 0.15 && echo 2 && sleep 0.1 && echo 3`
const p3 = $`cat`

p1.pipe(p3)
p2.pipe(p3)

setTimeout(() => p1.unpipe(p3), 150)

const { stdout } = await p3
// 'foo\n1\nbar\n2\n3\n'
Many-to-one piping

Multiple sources can now stream into a single destination. All sources complete before the destination closes. #​1300

const $h = $({ halt: true })
const p1 = $`echo foo`
const p2 = $h`echo a && sleep 0.1 && echo c && sleep 0.2 && echo e`
const p3 = $h`sleep 0.05 && echo b && sleep 0.1 && echo d`
const p4 = $`sleep 0.4 && echo bar`
const p5 = $h`cat`

await p1
p1.pipe(p5)
p2.pipe(p5)
p3.pipe(p5)
p4.pipe(p5)

const { stdout } = await p5.run()
// 'foo\na\nb\nc\nd\ne\nbar\n'
Piping from rejected processes

Processes that exit with errors can now still pipe their output. The internal recorder retains their stream, status, and exit code. #​1296

const p1 = $({ nothrow: true })`echo foo && exit 1`
await p1

const p2 = p1.pipe($({ nothrow: true })`cat`)
await p2

p1.output.toString() // 'foo\n'
p1.output.ok         // false
p1.output.exitCode   // 1

p2.output.toString() // 'foo\n'
p2.output.ok         // false
p2.output.exitCode   // 1
Components versions

Since zx bundles third-party libraries without their package.jsons, their versions weren’t previously visible. You can now access them via the versions static map — including zx itself. #​1298 #​1295

import { versions } from 'zx'

versions.zx     // 8.7.2
versions.chalk  // 5.4.1

v8.7.2: — Copper Crafter

Compare Source

Stability and customizability improvements

  • Handle nothrow option on ProcessPromise init stage #​1288
const o = await $({ nothrow: true })`\033`
o.ok      // false
o.cause   // Error
  • Handle _snapshot.killSignal value on kill() #​1287
const p = $({killSignal: 'SIGKILL'})`sleep 10`
await p.kill()
p.signal  // 'SIGKILL'
import { Fail } from 'zx'

Fail.EXIT_CODES['2'] = 'Custom error message'
Fail.formatErrorMessage = (err: Error, from: string): string =>
  `${err.message} (${from})`
import type { $, Options } from 'zx'

const custom$: $ = (pieces: TemplateStringsArray | Partial<Options>, ...args: any[]) => {
  // ... custom implementation
}

v8.7.1: — Pipe Whisperer

Compare Source

Continues v8.7.0: handles new ps() corner case and improves $.kill mechanics on Windows #​1266 #​1267 #​1269 webpod/ps#14

v8.7.0: — Solder Savior

Compare Source

Important fixes for annoying flaky bugs

kill() 🐞

We've found an interesting case #​1262

const p = $`sleep 1000`
const {pid} = p // 12345
await p.kill()

If we kill the process again, the result might be unexpected:

await ps({pid}) // {pid: 12345, ppid: 67890, command: 'another command', ...}
p.kill()

This happens because the pid may be reused by the system for another process, so we've added extra assertions to prevent indeterminacy:

p.kill()  // Error: Too late to kill the process.
p.abort() // Error: Too late to abort the process.
ps() 🐛
  • ps() uses wmic internally on Windows, it relies on fragile heuristics to parse the output. We have improved this logic to handle more format variants, but over time (in v9 maybe) we're planning to change the approach.

#​1256 #​1263 webpod/ps#12 webpod/ingrid#6

const [root] = await ps.lookup({ pid: process.pid })
assert.equal(root.pid, process.pid)

v8.6.2: — Flow Unstoppable

Compare Source

Fixes $.prefix & $.postfix values settings via env variables #​1261 #​1260

v8.6.1: — Drain Hero

Compare Source

  • Use process.env.SHELL as default shell if defined #​1252
SHELL=/bin/zsh zx script.js
  • Accept numeric strings as parseDuration() arg #​1249
await sleep(1000)   // 1 second
await sleep('1000') // 1 second

v8.6.0: — Valve Vanguard

Compare Source

  • Enabled thenable params processing for $ literals #​1237
const a1 = $`echo foo`
const a2 = new Promise((resolve) => setTimeout(resolve, 20, ['bar', 'baz']))

await $`echo ${a1} ${a2}` // foo bar baz

v8.5.5: — PVC Wizard

Compare Source

Minor feature polish.

  • ProcessPromise and ProcessOutput lines() getters now accept a custom delimiter #​1220 #​1218
const cwd = tempdir()
const delimiter = '\0'

const p1 = $({
  cwd
})`touch foo bar baz; find ./ -type f -print0 -maxdepth 1`
(await p1.lines(delimiter)).sort() // ['./bar', './baz', './foo']
  
// or via options
const lines = []
const p2 = $({
  delimiter,
  cwd,
})`find ./ -type f -print0 -maxdepth 1`

for await (const line of p2) {
  lines.push(line)
}

lines.sort() // ['./bar', './baz', './foo']

v8.5.4: — Pipe Dreamer

Compare Source

v8.5.3: — Trap Master

Compare Source

  • Another portion of JSR related improvements #​1193 #​1192
  • Goods refactoring #​1195
    • Fixes expBackoff implementation
    • Sets $.log.output as default spinner() output
    • Makes configurable question() I/O
  • Added Graaljs compatability test #​1194
  • Docs improvements, usage examples updates #​1198

v8.5.2: — Threaded Perfection

Compare Source

v8.5.0: — Flow Splitter

Compare Source

In this release we're significantly expanding the zx setup capabilities.

zx@​lite

Just core functions without extras, ~7x smaller than the full version.
#​1131

npm i zx@lite
npm i zx@8.5.0-lite

Detailed comparison: zx/versions

import { $ } from 'zx'
await $`echo foo`
Channels

We have completely reforged the distribution flow. Now zx is available in multiple formats:

##### npm pkg from registry.npmjs.org
npm i zx        

##### install directly from the GH
npm i google/zx 

##### from GH the npm registry
npm i --registry=https://npm.pkg.github.com @&#8203;google/zx

##### fetch from the JSR
##### https://jsr.io/docs/using-packages

##### @&#8203;webpod is temporary JSR scope until @&#8203;google/zx becomes ready, we'll migrate later
npx jsr add @&#8203;webpod/zx
deno add jsr:@&#8203;webpod/zx

##### homebrew formula
##### https://github.com/Homebrew/homebrew-core/blob/master/Formula/z/zx.rb
brew install zx

#​1141...
#​1157

Docker

If you'd prefer to run zx in a container, you can pull the image from the GH docker registry.
node:22-alpine is used as a base. #​1142 #​1145

docker pull ghcr.io/google/zx:8.5.0
docker run -t ghcr.io/google/zx:8.5.0 -e="await \$({verbose: true})\`echo foo\`"
docker run -t -i -v ./:/script ghcr.io/google/zx:8.5.0 script/t.js
Chores
  • Introduced fetch pipe helper to bypass string size limits #​1130 #​977
const p1 = fetch('https://example.com').pipe($`cat`)
const p2 = fetch('https://example.com').pipe`cat`
import { glob } from 'zx'
const packages = glob.sync(['package.json', 'packages/*/package.json'])
ZX_REGISTRY='https://custom-registry.example.com' zx script.js

v8.4.2

Compare Source

v8.4.1: – Rusty Elbow

Compare Source

Logger enhancements are arriving in this release. #​1119 #​1122 #​1123 #​1125

  • You can customize the output by defining your own formatters for each log entry kind.
$.log.formatters = {
  cmd: (entry: LogEntry) => `CMD: ${entry.cmd}`,
  fetch: (entry: LogEntry) => `FETCH: ${entry.url}`
  //...
}
  • Cmd highlighter now should properly detect bins and arguments. If still not, please report it in #​1122
  • Switched to TS 5.8 #​1120
  • Applied zizmor to check GHA workflows #​1126
  • Prettier is now enabled as a pre-commit hook #​1118

v8.4.0: – Drip Detective

Compare Source

Try the new batch of enhancements: npm i zx@8.4.0 https://www.npmjs.com/package/zx/v/8.4.0

Changes
  • The CLI option --prefer-local now allows linking both external binaries and packages #​1116 #​1117
const cwd = tmpdir()
const external = tmpdir()
await fs.outputJson(path.join(external, 'node_modules/a/package.json'), {
  name: 'a',
  version: '1.0.0',
  type: 'module',
  exports: './index.js',
})
await fs.outputFile(
  path.join(external, 'node_modules/a/index.js'),
  `
export const a = 'AAA'
`
)
const script = `
import {a} from 'a'
console.log(a);
`
const out = await $`zx --cwd=${cwd} --prefer-local=${external} --test <<< ${script}`
assert.equal(out.stdout, 'AAA\n')
  • The quote has been slightly changed for a conner case, when zx literal gets an array.
    #​999 #​1113
const p = $({prefix: '', postfix: ''})`echo ${[1, '', '*', '2']}`

// before
p.cmd //  `echo 1  $'*' 2`) 

// after
p.cmd //  `echo 1 $'' $'*' 2`) 
zx script.zx           # Unknown file extension "\.zx"
zx --ext=mjs script.zx # OK
const err = new Error('BrokenSpawn')
const o = await $({
  nothrow: true,
  spawn() {
    throw err
  },
})`echo foo`
o.ok       // false
o.exitCode // null
o.message  // BrokenSpawn...
o.cause    // err

v8.3.2: – Clogged Drain

Compare Source

Restrics unsafe vals usage on dotenv.stringify #​1093 #​1094

v8.3.1: – Perfect Seal

Compare Source

The release essence: introduced full-featured .env support #​461#​1060 #​1052 #​1043 #​1037 #​1032 #​1030 #​1022

API

envapi is a tiny 100 LOC dotenv-inspired parser and serializer that we've integrated into zx.

import { dotenv, fs } from 'zx'

// parse
const env = dotenv.parse('A=A\nFOO=BAR') // { A: 'A', FOO: 'BAR' }

// serialize
const raw = dotenv.stringify(env) // A=A\nFOO=BAR
await fs.writeFile('.env', raw)

// load
dotenv.load('.env') // { A: 'A', FOO: 'BAR' }

// update the process.env
dotenv.config('.env')
process.env.A // A
CLI
zx --env .env script.mjs
zx --env-file .env script.mjs
QnA

— Why not use dotenv directly?
— 1) Size does matter 2) We'd like to avoid internal vaults.

— Why not load .env by default?
— 1) Explicit is better than implicit 2) Runtime itself (like bun) may provide the feature.

Chore

Configuration

📅 Schedule: (in timezone America/Los_Angeles)

  • Branch creation
    • ""
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Nov 21, 2025

⚠️ No Changeset found

Latest commit: b6423c4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Nov 21, 2025

npm i https://pkg.pr.new/apollographql/apollo-client/@apollo/client@13029

commit: b6423c4

@apollo-librarian
Copy link
Copy Markdown
Contributor

apollo-librarian Bot commented Nov 21, 2025

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: 5b52379a782d1d2433d81b4e
Build Logs: View logs


✅ AI Style Review — No Changes Detected

No MDX files were changed in this pull request.

Review Log: View detailed log

This review is AI-generated. Please use common sense when accepting these suggestions, as they may not always be accurate or appropriate for your specific context.

@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 3 times, most recently from b24bb97 to fb11f21 Compare December 3, 2025 14:57
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 5 times, most recently from b1b8b72 to ec62076 Compare December 16, 2025 17:01
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 9 times, most recently from 3b6b983 to 58a4bcd Compare December 22, 2025 18:38
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 4 times, most recently from 005f3f2 to 3d10a9a Compare January 12, 2026 09:17
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 5 times, most recently from f4706d6 to fbc5d68 Compare January 15, 2026 23:17
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 4 times, most recently from 4bb2573 to 5a67cd6 Compare February 4, 2026 08:35
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 9 times, most recently from 0e27e4e to de1d4c5 Compare February 10, 2026 22:22
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch 6 times, most recently from d5cd325 to 3714d56 Compare February 23, 2026 18:29
@renovate renovate Bot enabled auto-merge (squash) March 17, 2026 11:22
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch from 3714d56 to 27c48bd Compare March 17, 2026 11:22
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch from 27c48bd to 3e62f5f Compare March 26, 2026 22:03
@renovate renovate Bot changed the title chore(deps): update dependency zx to v8.8.5 [security] chore(deps): update dependency zx to v8.8.5 [security] - autoclosed Mar 27, 2026
@renovate renovate Bot closed this Mar 27, 2026
auto-merge was automatically disabled March 27, 2026 01:04

Pull request was closed

@renovate renovate Bot deleted the renovate/npm-zx-vulnerability branch March 27, 2026 01:04
@renovate renovate Bot changed the title chore(deps): update dependency zx to v8.8.5 [security] - autoclosed chore(deps): update dependency zx to v8.8.5 [security] Mar 30, 2026
@renovate renovate Bot reopened this Mar 30, 2026
@renovate renovate Bot force-pushed the renovate/npm-zx-vulnerability branch from 3e62f5f to 566b67c Compare March 30, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants