Repository navigation
fix(config): redact credentials in proxy env vars and empty-password userinfo - #10221
Open
itsgaldoron wants to merge 1 commit into
Open
itsgaldoron wants to merge 1 commit into
itsgaldoron wants to merge 1 commit into
Conversation
…userinfo The environment-related config section of `npm config list` echoed the raw values of HTTP_PROXY/HTTPS_PROXY/NO_PROXY, bypassing the redact() helper used by the rest of the output (issue npm#9773). Additionally, redact() leaves userinfo with an empty password untouched (`https://ci-token:@host`, the usual token-as-username CI proxy shape), so such values were printed verbatim in both the config-value display and the env-var section. Compose a redactUserinfo() step with redact() at every `config list` display point and in isPrivate(), so config list --json omits the value and config get rejects it like any other credential-bearing value. Regression tests cover both credential shapes plus credential-less controls. Signed-off-by: Doron Gal <dorongal1@gmail.com>
itsgaldoron
force-pushed
the
fix-config-redact-proxy-env-credentials
branch
from
November 4, 2026 12:30
7b9fb26 to
347c7d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(config): redact credentials in proxy env vars and empty-password userinfo
Fixes #9773.
Root cause
npm config listdisplays credentials in two ways:The
; environment-related configsection echoes the raw values of theHTTP_PROXY/HTTPS_PROXY/NO_PROXYenvironment variables withJSON.stringify(process.env[key]), bypassing theredact()helper that therest of the output uses. A proxy URL with a password is printed verbatim
(issue [BUG] npm config list leaks credentials in proxy-related environment variables #9773's repro).
Everything
redact()covers still leaks one credential shape: userinfo withan empty password, e.g.
https://ci-token:@proxy.example.com— the usual"token as the userinfo" CI/proxy form.
@npmcli/redact'sredactUrlPasswordMatcheronly fires whenurl.passwordis truthy, so thisvalue passes through unchanged and is printed in both the config-value
display and the env-var section.
Fix
redact()like the config-value displayalready does.
redactUserinfo()and compose it withredact()at everyconfig listdisplay point (
displayVar, the env-var section) and inisPrivate(), soconfig list --jsonomits the value andconfig getrejects it exactly likeany other credential-bearing value (
user:pass@…URLs already behave thisway). When a URL has userinfo and no password, the userinfo is masked to
***@(matching the existinguser:***@convention for non-empty passwords).Behavior change (what changes for users)
isPrivate()now also fires on a URL that carries a username and an emptypassword, so such a value is treated exactly like any other credential-bearing
value. Measured on a clean pair of trees (base
10ffa9fvs this PR):proxy=https://mytoken:@proxy.example.comconfig list --json,config get proxyreturns itproxy = "https://***@proxy.example.com", omitted from--json,config get proxyerrorsThe proxy option is protectedproxy=http://user:pass@example.com:80http://user:***@example.com:80https-proxy=https://secure-proxy.example.com:8443(no userinfo)proxy=https://anonymous:@proxy.example.com(username, no secret)config getreturns ithttps://***@proxy.example.com,config getrejects itThat last row is the honest edge of the change: any username-plus-empty-password
URL is now private, not only ones whose username looks like a token. We think that
is the right trade — the shape is indistinguishable from a credential at display
time — but it is a real behavior change for anyone storing a username-only URL in
npm config, and
config getwill now refuse to print it back.Repro / test output (fail-before, on unpatched
latest@ 10ffa9f)Pass-after (with this patch)
Full unit suite both sides (tap --no-coverage, 124 suites):
unpatched
Suites: 124 passed · Asserts: 6036 passed, 7 skip, of 6043;patched
Suites: 124 passed · Asserts: 6047 passed, 7 skip, of 6054— thedelta is exactly the 11 new assertions, zero regressions.
Control
NO_PROXY=localhost,127.0.0.1andhttps-proxy=https://secure-proxy.example.com:8443(no userinfo) are asserted unchanged in the same tests, so the redaction only
touches values that actually carry userinfo credentials.
What we are NOT claiming
@npmcli/redactitself: the empty-password userinfo gapexists in the library's
redactUrlPasswordMatcherand is worth fixingupstream for every consumer. This PR makes
npm config list(issue [BUG] npm config list leaks credentials in proxy-related environment variables #9773'ssurface) safe either way.
npm config getfor values thatdo not carry credentials.
Supersede disclosure
This supersedes #9774 (thank you @tianrking for the original diagnosis; we posted
a takeover note there and will close this PR in favour of theirs if they want to
land it themselves), which
applies
redact()to the env-var section. That patch is necessary but notsufficient: with it applied,
https://ci-token:@proxy.example.comis stillprinted verbatim in both display sections. This PR keeps that fix and adds the
missing userinfo handling plus tests for both credential shapes. No other open
PR touches this surface (#9432 redacts argv logs, #10041/#9874 fix JSON output
escaping, #10072 redacts error details — different root causes).
🤖 Generated with Claude Code