# pnpm Has Lockfile Integrity Bypass that Allows Remote Dynamic Dependencies

pnpm stores HTTP/git tarball dependencies in the lockfile without integrity hashes, letting the remote server serve different code on each install despite a committed lockfile.

- Payout: Research
- Severity: high
- Program: pnpm
- Found by: orenyomtov
- Disclosed: 2026-01-07
- CVE: CVE-2025-69263
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-7vhp-vf5g-r2fw
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-7vhp-vf5g-r2fw
- Tags: area:oss domain:oss impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:misconfiguration

**Target:** pnpm package manager tarball resolver / lockfile
**Root cause:** The tarball resolver returns only the resolved URL for HTTP and git tarball dependencies without computing an integrity hash, so the lockfile entry has no integrity field to verify against.
**Steps:**
1. Add a dependency pointing at an HTTP tarball, e.g. `"pkg": "https://example.com/pkg.tgz"`, or a git shorthand/URL like `github:user/repo`.
2. Install so pnpm writes a lockfile entry such as `remote-dynamic-dependency@http://example.com/pkg.tgz: resolution: {tarball: http://example.com/pkg.tgz}` with no integrity field.
3. Run `pnpm store prune` and reinstall; the server returns different tarball content each request and pnpm accepts it since there is nothing to verify.
4. Run the attached PoC via `cd pnpm-bypass-integrity-poc && ./run-poc.sh` to observe differing code downloaded per install despite the committed lockfile.
**How found:** Code reading of `resolving/tarball-resolver/src/index.ts` revealed the resolver returns `{tarball: resolvedUrl}` with no integrity field, prompting a check of the resulting lockfile entry and a PoC with a rotating-content server.
**Exploitation:** An attacker publishes a package whose dependency tree includes an HTTP/git tarball they control. The server serves benign content during review/audit and malicious content to targeted victims or CI environments, selected by request metadata (IP, headers, timing). The victim's committed lockfile provides no integrity protection, so the swapped payload installs silently.
**Escalation:** Payload can be varied per request to evade audits and target specific environments, and mutated over time for persistent supply chain compromise.
**Insight:** When auditing package managers, check whether every resolution path (not just the primary registry) populates the lockfile integrity field; alternate resolvers like raw URL and git tarballs are common gaps where lockfile guarantees silently vanish.

## Proof of concept (copied exactly from the original report)

**Lockfile entry lacking integrity hash**

```
remote-dynamic-dependency@http://example.com/pkg.tgz:
  resolution: {tarball: http://example.com/pkg.tgz}
```

**Tarball resolver returning no integrity**

```
return {
  resolution: {
    tarball: resolvedUrl,
    // No integrity field
  },
  resolvedVia: 'url',
}
```

**PoC run script invocation**

```
cd pnpm-bypass-integrity-poc
./run-poc.sh
```

