Описание
pnpm binds unscoped user-level npm auth credentials to a repository-selected registry
Summary
pnpm can send user-level unscoped npm authentication credentials to a registry chosen by a repository-local .npmrc file.
In the reproduced case, the user's npm config contains a default registry and an unscoped _authToken. The repository does not provide a token-bearing auth line. It only sets registry= to a different registry URL. During normal pnpm metadata/install workflows, pnpm binds the user-origin unscoped credential to the repository-selected registry and sends it as an Authorization header.
This was reproduced with fake credentials and loopback registries only. No third-party registry or real token was used.
Affected Behavior Observed
Observed affected:
- pnpm
10.33.2:pnpm install --ignore-scriptssends the user-level unscoped_authTokento the repository-selected registry. - pnpm
11.1.3:pnpm install --ignore-scriptssends the user-level unscoped_authTokento the repository-selected registry. - pnpm
11.2.1(next-11dist tag at testing time):pnpm install --ignore-scriptssends the user-level unscoped_authTokento the repository-selected registry. - pnpm
11.1.3:pnpm viewalso sends user-level unscoped_authToken,_auth, andusername/_passwordcredentials to the repository-selected registry in the local loopback replay.
Control:
- npm
10.9.7rejects the same unscoped user_authTokenconfiguration withERR_INVALID_AUTHand does not send anAuthorizationheader to the repository-selected registry. - URL-scoped registry token controls held in the local loopback replay: tokens scoped to the trusted registry URL were not sent to the attacker registry.
Threat Model
Victim:
- developer or CI job with user-level npm registry credentials configured;
- runs
pnpm install,pnpm view, or an equivalent pnpm metadata/restore command in a repository.
Attacker:
- controls repository-local package manager configuration, such as
.npmrc; - can set
registry=to a registry endpoint they control; - does not need to provide a token-bearing auth line for the strong case.
Boundary:
Credentials from a higher-trust user configuration should not be rebound to a lower-trust repository-selected registry unless the credential is explicitly scoped to that registry.
Minimal Reproduction
The reproducer below starts two loopback HTTP registries:
- a trusted registry URL used in the isolated user
.npmrc; - an attacker registry URL used in the repository-local
.npmrc.
The isolated user .npmrc contains:
The repository-local .npmrc contains:
The repository package.json depends on a toy package served by the loopback registry. The script then runs:
Expected Safe Behavior
pnpm should not send the user-level unscoped _authToken to the repository-selected registry. A safe behavior would be to reject or ignore the unscoped credential in this lower-trust registry-rebinding situation and require the credential to be URL-scoped to the selected registry.
Observed Behavior
pnpm 10.33.2, pnpm 11.1.3, and pnpm 11.2.1 send:
to the attacker loopback registry during install. npm 10.9.7 rejects the same config and sends no Authorization header.
Security Impact
This can disclose npm registry credentials from user-level configuration to a registry endpoint selected by an untrusted repository. The leak occurs before package lifecycle scripts run and does not depend on package code execution.
Non-Claims
This report does not claim:
- remote code execution;
- registry account compromise by itself;
- leakage of URL-scoped tokens for a different registry;
- npm CLI impact;
- impact from a repository explicitly committing its own token-bearing auth line.
Source-Level Notes
In pnpm's config/auth-header flow, unscoped/default credentials are parsed from the merged auth config and stored as default credentials. The auth-header logic then maps those default credentials to the effective default registry. Because repository-local .npmrc can change the effective default registry, higher-trust default credentials can be applied to a lower-trust registry choice.
Suggested Fix Direction
The conservative fix direction is to reject or contain unscoped/default auth credentials when a lower-trust workspace/repository config changes the default registry. A compatibility-preserving fix could track the source layer of both the default registry and the default credentials, then only bind default credentials to a registry selected by the same or higher-trust source. A stricter npm-compatible fix would reject unscoped auth and require URL-scoped credentials.
This needs maintainer semantic review and compatibility control because some legacy workflows may intentionally rely on default/unscoped auth.
Runnable Reproducer
Save the following as repro.py and run it with Python 3 in an environment with pnpm and npm available. To force a specific pnpm version through Corepack, set PR166_PNPM_SPEC, for example PR166_PNPM_SPEC=11.2.1.
Abbreviated Expected Output
Reporter: JUNYI LIU
Пакеты
pnpm
< 10.34.0
10.34.0
pnpm
>= 11.0.0, < 11.4.0
11.4.0
Связанные уязвимости
pnpm is a package manager. Prior to 10.34.0 and 11.4.0, pnpm can send user-level unscoped npm authentication credentials to a registry chosen by a repository-local .npmrc file. In the reproduced case, the user's npm config contains a default registry and an unscoped _authToken. The repository does not provide a token-bearing auth line. It only sets registry= to a different registry URL. During normal pnpm metadata/install workflows, pnpm binds the user-origin unscoped credential to the repository-selected registry and sends it as an Authorization header. This vulnerability is fixed in 10.34.0 and 11.4.0.
pnpm is a package manager. Prior to 10.34.0 and 11.4.0, pnpm can send user-level unscoped npm authentication credentials to a registry chosen by a repository-local .npmrc file. In the reproduced case, the user's npm config contains a default registry and an unscoped _authToken. The repository does not provide a token-bearing auth line. It only sets registry= to a different registry URL. During normal pnpm metadata/install workflows, pnpm binds the user-origin unscoped credential to the repository-selected registry and sends it as an Authorization header. This vulnerability is fixed in 10.34.0 and 11.4.0.
pnpm is a package manager. Prior to 10.34.0 and 11.4.0, pnpm can send ...