## Summary
pnpm passes the lockfile-controlled git `resolution.commit` value to `git fetch` without a `--` separator or commit-format validation. For git dependencies fetched through the shallow-fetch path, a malicious lockfile can replace the expected 40-character commit hash with a Git option such as `--upload-pack=<command>`. For SSH and local transports, `--upload-pack` can execute the supplied command. HTTPS transports ignore `--upload-pack`, so the practical attack surface is primarily SSH or local git dependencies.
## Vulnerability Details
The vulnerable path is in `fetching/git-fetcher/src/index.ts`. When a git dependency host is configured for shallow fetching, pnpm calls:
```typescript
await execGit(['fetch', '--depth', '1', 'origin', resolution.commit], { cwd: tempLocation })
```
Because `resolution.commit` is appended before a `--` separator, Git can parse a commit value beginning with `-` as an option. The same file later passes the value to `git checkout` without a separator:
```typescript
await execGit(['checkout', resolution.commit], { cwd: tempLocation })
```
`resolution.commit` comes from the lockfile and is typed as a plain `string`; pnpm does not validate it as a 40-character hexadecimal commit before passing it to Git.
## Proof of Concept
```bash
bash autofyn_audit/exploits/vuln11_git_upload_pack_rce/exploit.sh
# Creates a local bare git repo and triggers the shallow-fetch path.
# Replaces the lockfile commit hash with '--upload-pack=touch /tmp/vuln11_pwned'.
# Result: PASS -- /tmp/vuln11_pwned created by injected touch command.
```
The PoC uses a local `file://githost/...` repository because the injection requires a local or SSH transport. HTTPS transport ignores `--upload-pack`.
## Impact
Code execution as the user running `pnpm install`, under specific transport conditions. The attacker must modify `pnpm-lock.yaml`, and the affected dependency must use SSH or local git transport. HTTPS transport (the common case) is immune.
## Suggested Remediation
Add a `--` separator before lockfile-controlled git revision values. Validate `resolution.commit` matches `/^[0-9a-f]{40}$/i` before passing to Git.
---
> Discovered by [AutoFyn](https://github.com/SignalPilot-Labs/AutoFyn)
> Full audit report: [audit_report.md](https://github.com/tempcollab/pnpm/blob/main/autofyn_audit/audit_report.md)
> Exploit script: [exploit.sh](https://github.com/tempcollab/pnpm/blob/main/autofyn_audit/exploits/vuln11_git_upload_pack_rce/exploit.sh)
### Summary
A malicious `codeload.github.com` server can serve whatever tarball it wants and pnpm will install it regardless of the lockfile.
### Details
The lockfile does not store the hash of the dependencies from https://codeload.github.com
This means that if this server was compromised or a person's machine configuration was compromised, pnpm would download and install these dependencies.
### PoC
```sh
> pnpm -v
10.28.2
```
Given the following package.json:
```json
{
"dependencies": {
"add": "git://github.com/dsherret/npm-git-dep.git#b3eeb9b"
}
}
```
This produces a lockfile like so:
```yaml
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
add:
specifier: git://github.com/dsherret/npm-git-dep.git#b3eeb9b
version: https://codeload.github.com/dsherret/npm-git-dep/tar.gz/b3eeb9b
packages:
add@https://codeload.github.com/dsherret/npm-git-dep/tar.gz/b3eeb9b:
resolution: {tarball: https://codeload.github.com/dsherret/npm-git-dep/tar.gz/b3eeb9b}
version: 1.0.0
snapshots:
add@https://codeload.github.com/dsherret/npm-git-dep/tar.gz/b3eeb9b: {}
```
Notice that there is no hash. The `b3eeb9b` is not sufficient because I can configure my machine to resolve a compromised tarball from that url (I tested it out and pnpm just installs it).
### Impact
Anyone relying on github git dependencies.
pnpm versions prior to 9.15.0 contain a vulnerability where the use of overrides combined with global cache handling allows one workspace to poison the global cache and execute scripts in another workspace, even when 'ignore-scripts' is enabled. This undermines the expected prevention of script execution during package installs. The issue is fixed in version 9.15.0. A recommended workaround is to use separate cache and store directories for each workspace.
pnpm versions 6.25.0 through 10.26.2 are affected by a command injection vulnerability via environment variable substitution in .npmrc configuration files with tokenHelper settings. This flaw allows an attacker with control over environment variables during pnpm operations to execute remote code in build environments. The vulnerability is fixed in version 10.27.0.
pnpm versions 10.26.0 and earlier have a vulnerability where HTTP and git-hosted tarball dependencies in the lockfile lack integrity hashes. This flaw allows a remote server to serve different code on each install, bypassing lockfile protections. An attacker can publish a package with such dependencies and serve varying code to different users or CI/CD environments. The issue is fixed starting from version 10.26.0.
pnpm versions 10.0.0 through 10.25 contain a vulnerability that allows git-hosted dependencies to execute arbitrary code during installation by bypassing the default disablement of dependency lifecycle scripts. This occurs because git dependencies can run prepare, prepublish, and prepack scripts during the fetch phase. The issue is fixed in pnpm version 10.26.0.
A path traversal vulnerability exists in pnpm's binary fetcher prior to version 10.28.1. This flaw allows crafted ZIP packages to write files outside the intended extraction directory by using '../' sequences or absolute paths in ZIP entries, or by manipulating the BinaryResolution.prefix field. Exploitation can lead to overwriting sensitive files and potentially remote code execution. The issue is fixed in pnpm version 10.28.1.
pnpm versions prior to 10.28.1 contain a Windows-specific path traversal vulnerability in tarball extraction. The vulnerability allows malicious packages to write files outside the intended directory on Windows systems by bypassing path normalization checks. This can lead to overwriting critical files such as .npmrc or build configuration files, affecting Windows users and CI/CD pipelines using Windows runners. The issue is patched in version 10.28.1.
A path traversal vulnerability in pnpm before version 10.28.1 allows malicious npm packages to create executable files outside the intended node_modules/.bin directory. This happens because bin names starting with '@' bypass validation, leaving path traversal sequences intact after scope normalization. The vulnerability can be exploited to overwrite configuration files, scripts, or other sensitive files. The issue is fixed in pnpm version 10.28.1.
pnpm versions prior to 10.28.2 contain a symlink traversal vulnerability affecting file: and git: dependencies. This flaw allows malicious packages to follow symlinks beyond the package root during installation, potentially copying sensitive local files such as /etc/passwd or SSH private keys into node_modules. Registry packages are not impacted. The vulnerability is patched in version 10.28.2.
pnpm versions prior to 10.28.2 contain a path traversal vulnerability in the handling of the directories.bin field of packages. This vulnerability allows a malicious package to specify a path outside the package root, causing pnpm to change file permissions (chmod 755) on arbitrary files on Unix-like systems. Windows systems are not affected. The issue is fixed in version 10.28.2.
pnpm versions prior to 10.34.0 and 11.4.0 have a vulnerability in their patch application process that allows attackers to write or delete arbitrary files via malicious patch files containing path traversal sequences. This flaw arises because the patch application does not validate file paths extracted from .patch files, enabling directory traversal outside the intended package directory during installation. The issue is fixed in versions 10.34.0 and 11.4.0.
pnpm versions prior to 10.34.0 and 11.4.0 have a vulnerability where a transitive dependency alias can include path traversal segments. This flaw allows an attacker to cause pnpm to replace paths in the current project with symlinks to attacker-controlled directories during installation, even if scripts are ignored. The issue is fixed in versions 10.34.0 and 11.4.0.
pnpm versions prior to 10.34.0 and 11.4.0 can unintentionally send user-level unscoped npm authentication tokens to a registry specified only by a repository-local .npmrc file. This occurs when the user's npm config has a default registry and an unscoped _authToken, but the repository sets a different registry URL without its own token. As a result, the user's token is bound to the repository's registry and sent as an Authorization header during package operations, potentially exposing credentials to unintended registries. The issue is fixed in pnpm versions 10.34.0 and 11.4.0.
A vulnerability in pnpm before versions 10.34.0 and 11.4.0 allows bypassing integrity checks during package installation if the integrity field is missing from the lockfile. This can lead to installation of altered packages without detection when using the --frozen-lockfile option. The issue is specific to pnpm and differs from npm's default integrity enforcement. The vulnerability is fixed in versions 10.34.0 and 11.4.0.
pnpm versions prior to 10.34.0 and 11.4.0 contain a vulnerability where the package integrity check can be bypassed in non-frozen mode. This allows pnpm to accept and install altered package tarballs from the registry if they keep the same name and version, undermining lockfile integrity. The issue is fixed in versions 10.34.0 and 11.4.0.
A vulnerability in the pnpm package manager prior to versions 10.34.2 and 11.5.3 allows malicious repository configurations to expand environment variable placeholders into registry requests. This can lead to victim environment secrets being sent to attacker-controlled registries before lifecycle scripts run. The issue has been fixed in versions 10.34.2 and 11.5.3.
A vulnerability in the pnpm package manager prior to versions 10.34.2 and 11.5.3 allows attackers to spoof manifest identity by exploiting the generic peer-suffix normalizer. This flaw can cause one source string approval to authorize a different attacker-controlled source with a normalized locator value, potentially leading to execution of attacker lifecycle scripts. The issue is fixed in versions 10.34.2 and 11.5.3.