Doc says: https://nodejs.org/api/http.html#no-proxy-format
.example.com - Domain suffix match (matches sub.example.com)
But .example.com also matches totally-not-example.com.
Also (more trivially verifiable), .ample.com matches example.com:
% cat deepview-broken-proxy.js
require('node:https').request('https://example.com', (res) => {
console.log('status:', res.statusCode)
process.exit(0)
}).end()
% HTTPS_PROXY='http://10.0.0.0:1' node --use-env-proxy deepview-broken-proxy.js
node:events:487
throw er; // Unhandled 'error' event
^
Error [ERR_PROXY_TUNNEL]: Connection to establish proxy tunnel timed out after 5000ms
...
% HTTPS_PROXY='http://10.0.0.0:1' NO_PROXY='.ample.com' node --use-env-proxy deepview-broken-proxy.js
status: 200
https://github.com/nodejs/node/blob/HEAD/lib/internal/http.js#L161
Details
In ProxyConfig#shouldUseProxy (the transitive helper that checkShouldUseProxy always delegates to), the .suffix bypass-list rule uses host.endsWith(suffix) after stripping the leading dot. This matches across domain-label boundaries: a NO_PROXY=.example.com rule causes checkShouldUseProxy(..., { host: 'evilexample.com' }) to return false (bypass proxy) because 'evilexample.com'.endsWith('example.com') is true. An attacker who can choose/influence the target hostname can therefore route traffic around a proxy that was meant to intercept all *.example.com traffic. The check should require the character immediately preceding the suffix to be . (or the host to equal the suffix exactly), e.g. host === suffix || host.endsWith('.' + suffix) — or reuse the same form as the *.example.com branch (which is already safe because its effective suffix retains the leading dot).
Doc says: https://nodejs.org/api/http.html#no-proxy-format
But
.example.comalso matchestotally-not-example.com.Also (more trivially verifiable),
.ample.commatchesexample.com:https://github.com/nodejs/node/blob/HEAD/lib/internal/http.js#L161
Details