Skip to content

Commit 9b6af26

Browse files
mcollinaaduh95
authored andcommitted
lib,test: redact proxy credentials in tunnel errors
Refs: https://hackerone.com/reports/3720313 Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: nodejs-private/node-private#867 Backport-PR-URL: nodejs-private/node-private#894 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> CVE-ID: CVE-2026-48615
1 parent ad8a10c commit 9b6af26

2 files changed

Lines changed: 19 additions & 2 deletions

File tree

lib/internal/http.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ function ipToInt(ip) {
9898
/**
9999
* Represents the proxy configuration for an agent. The built-in http and https agent
100100
* implementation have one of this when they are configured to use a proxy.
101-
* @property {string} href - Full URL of the proxy server.
101+
* @property {string} href - Proxy server URL with credentials redacted.
102102
* @property {string} host - Full host including port, e.g. 'localhost:8080'.
103103
* @property {string} hostname - Hostname without brackets for IPv6 addresses.
104104
* @property {number} port - Port number of the proxy server.
@@ -109,13 +109,27 @@ function ipToInt(ip) {
109109
*/
110110
class ProxyConfig {
111111
constructor(proxyUrl, keepAlive, noProxyList) {
112-
const { host, hostname, port, protocol, username, password } = new URL(proxyUrl);
112+
let parsedUrl;
113+
try {
114+
parsedUrl = new URL(proxyUrl);
115+
} catch {
116+
throw new ERR_PROXY_INVALID_CONFIG(`Invalid proxy URL: ${proxyUrl}`);
117+
}
118+
const { host, hostname, port, protocol, username, password } = parsedUrl;
113119
this.href = proxyUrl; // Full URL of the proxy server.
114120
this.host = host; // Full host including port, e.g. 'localhost:8080'.
115121
this.hostname = hostname.replace(/^\[|\]$/g, ''); // Trim off the brackets from IPv6 addresses.
116122
this.port = port ? NumberParseInt(port, 10) : (protocol === 'https:' ? 443 : 80);
117123
this.protocol = protocol; // Protocol of the proxy server, e.g. 'http:' or 'https:'.
118124

125+
if (username || password) {
126+
parsedUrl.username = '';
127+
parsedUrl.password = '';
128+
this.href = parsedUrl.href;
129+
} else {
130+
this.href = proxyUrl;
131+
}
132+
119133
if (username || password) {
120134
// If username or password is provided, prepare the proxy-authorization header.
121135
const auth = `${decodeURIComponent(username)}:${decodeURIComponent(password)}`;

test/client-proxy/test-https-proxy-request-auth-failure.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const { code, signal, stderr } = await runProxiedRequest({
5353
// The proxy client should get an error from proxy authentication failure.
5454
// Since the process exits cleanly but with an error, check for any error output
5555
assert.match(stderr, /407 Proxy Authentication Required/);
56+
assert.match(stderr, /via http:\/\/localhost:\d+\/?/);
57+
assert.doesNotMatch(stderr, /baduser/);
58+
assert.doesNotMatch(stderr, /badpass/);
5659
assert.strictEqual(code, 0);
5760
assert.strictEqual(signal, null);
5861

0 commit comments

Comments
 (0)