GitHub Advisoryadvisory · npm

GHSA-379q-355j-w6rj pnpm v10+ Bypass "Dependency lifecycle scripts execution disabled by default"

HIGH Published 2026-01-07 Modified 2026-01-08 Official page ↗
Aliases
CVE-2025-69264
Ecosystem
npm
Packages
pnpm
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Weaknesses
CWE-693
Reviewed
2026-01-07

Affected packages

• npm pnpm: >= 10.0.0, < 10.26.0 → fixed in 10.26.0

Description

pnpm v10+ Git Dependency Script Execution Bypass Summary A security bypass vulnerability in pnpm v10+ allows git-hosted dependencies to execute arbitrary code during `pnpm install`, circumventing the v10 security feature "Dependency lifecycle scripts execution disabled by default". While pnpm v10 blocks `postinstall` scripts via the `onlyBuiltDependencies` mechanism, git dependencies can still execute `prepare`, `prepublish`, and `prepack` scripts during the fetch phase, enabling remote code execution without user consent or approval. Details pnpm v10 introduced a security feature to disable dependency lifecycle scripts by default (PR #8897). This is implemented by setting `onlyBuiltDependencies = []` when no build policy is configured: File: `pkg-manager/core/src/install/extendInstallOptions.ts` (lines 290-291) ```typescript if (opts.neverBuiltDependencies == null && opts.onlyBuiltDependencies == null && opts.onlyBuiltDependenciesFile == null) { opts.onlyBuiltDependencies = [] } ``` This creates an allowlist that blocks all packages from running scripts during the BUILD phase in `exec/build-modules/src/index.ts`. However, git-hosted dependencies are processed differently. During the FETCH phase, git packages are prepared using `preparePackage()`: File: `exec/prepare-package/src/index.ts` (lines 28-57) ```typescript export async function preparePackage (opts: PreparePackageOptions, gitRootDir: string, subDir: string) { // ... if (opts.ignoreScripts) return { shouldBeBuilt: true, pkgDir } // Only checks ignoreScripts, not onlyBuiltDependencies const execOpts: RunLifecycleHookOptions = { // ... rawConfig: omit(['ignore-scripts'], opts.rawConfig), // Explicitly removes ignore-scripts! } // Runs npm/pnpm install await runLifecycleHook(installScriptName, manifest, execOpts) // Runs prepare scripts for (const scriptName of PREPUBLISH_SCRIPTS) { // ['prepublish', 'prepack', 'publish'] await runLifecycleHook(newScriptName, manifest, execOpts) } } ``` The `ignoreScripts` option defaults to `false` and is completely separate from `onlyBuiltDependencies`. The `onlyBuiltDependencies` allowlist is never consulted during the fetch phase. Affected scripts that execute during fetch: • `prepare` • `prepublish` • `prepack` Attack vectors: • `git+https://github.com/attacker/malicious.git` • `github:attacker/malicious` • `gitlab:attacker/malicious` • `bitbucket:attacker/malicious` • `git+ssh://[email protected]/attacker/malicious.git` • `git+file:///path/to/local/repo` PoC Prerequisites: • pnpm v10.0.0 or later (tested on v10.23.0 and v11.0.0-alpha.1) • git Steps to reproduce: 1. Extract the attached poc.zip 2. Run the PoC script: ```bash cd poc chmod +x run-poc.sh ./run-poc.sh ``` 3. Verify the marker file was created by the malicious script: ```bash cat /tmp/pnpm-vuln-poc-marker.txt ``` Manual reproduction: 1. Create a malicious package with a `prepare` script: ```json { "name": "malicious-pkg", "version": "1.0.0", "scripts": { "prepare": "node -e \"require('fs').writeFileSync('/tmp/pwned.txt', 'RCE!')\"" } } ``` 2. Initialize it as a git repo and commit the files 3. Create a victim project that depends on it (just have to make sure it actually git clones and not just downloads a tarball): ```json { "dependencies": { "malicious-pkg": "git+file:///path/to/malicious-pkg" } } ``` 4. Run `pnpm install` - the prepare script executes without any warning or approval prompt Impact Severity: High Who is impacted: • All pnpm v10+ users • Users who believed they were protected by the v10 "scripts disabled by default" feature • CI/CD pipelines Attack scenarios: 1. Supply chain attack: An attacker compromises a dependency, adding to it a malicious git dependency that executes arbitrary code during `pnpm install` What an attacker can do: • Execute arbitrary code with the victim's privileges • Exfiltrate environment variables, secrets, and credentials • Modify source code or inject backdoors • Establish persistence or reverse shells • Access the filesystem and network Why this bypasses security expectations: • pnpm v10 changelog explicitly states "Lifecycle scripts of dependencies are not executed during installation by default" • Users expect git dependencies to follow the same security model as npm registry packages • There is no warning that git dependencies are treated differently • The `onlyBuiltDependencies` configuration does not affect git dependencies

Related

Alias · CVE (1)

Weakness · CWE (1)

  • CWE-693 Protection Mechanism Failure weakness

References