https: bind identity checks to session reuse

PR-URL: https://github.com/nodejs-private/node-private/pull/904
Refs: https://hackerone.com/reports/3811980
CVE-ID: CVE-2026-58040
This commit is contained in:
Matteo Collina authored and RafaelGSS committed 2026-07-29 10:41:22 -03:00
1 parent b413a9afec
commit 52a8ace880
3 files changed
+159 -2

No files matched your search

+42 -2
View File
@@ -35,6 +35,7 @@ const {
ObjectSetPrototypeOf,
ReflectApply,
ReflectConstruct,
Symbol,
SymbolAsyncDispose,
} = primordials;
@@ -48,6 +49,8 @@ const { ERR_PROXY_TUNNEL } = require('internal/errors').codes;
assertCrypto();
const tls = require('tls');
const kPerRequestCheckServerIdentity = Symbol('per-request checkServerIdentity');
let perRequestCheckServerIdentityIndex = 0;
const {
kProxyConfig,
checkShouldUseProxy,
@@ -281,6 +284,8 @@ function establishTunnel(agent, socket, options, tunnelConfig, afterSocket) {
tunneldSocket.removeListener('error', onTLSHandshakeError);
afterSocket(null, tunneldSocket);
});
if (requestOptions[kPerRequestCheckServerIdentity])
tunneldSocket[kPerRequestCheckServerIdentity] = true;
tunneldSocket.on('free', () => {
debug('Propagate free event from tunneled socket to tunnel socket');
socket.emit('free');
@@ -349,7 +354,9 @@ function createConnection(...args) {
debug('createConnection', options);
if (options._agentKey) {
const reuseSession = options._agentKey &&
!options[kPerRequestCheckServerIdentity];
if (reuseSession) {
const session = this._getSession(options._agentKey);
if (session) {
debug('reuse session for %j', options._agentKey);
@@ -416,7 +423,10 @@ function createConnection(...args) {
socket[kWaitForProxyTunnel] = true;
}
if (options._agentKey) {
if (options[kPerRequestCheckServerIdentity])
socket[kPerRequestCheckServerIdentity] = true;
if (reuseSession) {
// Cache new session for reuse
socket.on('session', (session) => {
this._cacheSession(options._agentKey, session);
@@ -471,6 +481,12 @@ function Agent(options) {
ObjectSetPrototypeOf(Agent.prototype, HttpAgent.prototype);
ObjectSetPrototypeOf(Agent, HttpAgent);
Agent.prototype.createConnection = createConnection;
Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) {
if (socket[kPerRequestCheckServerIdentity])
return false;
return FunctionPrototypeCall(HttpAgent.prototype.keepSocketAlive, this, socket);
};
function getPfxAgentKey(pfx, passphrase) {
if (!ArrayIsArray(pfx))
@@ -579,6 +595,9 @@ Agent.prototype.getName = function getName(options = kEmptyObject) {
if (options.privateKeyEngine)
name += options.privateKeyEngine;
if (options[kPerRequestCheckServerIdentity])
name += `:${options[kPerRequestCheckServerIdentity]}`;
return name;
};
@@ -619,6 +638,20 @@ Agent.prototype._evictSession = function _evictSession(key) {
const globalAgent = getGlobalAgent(getOptionValue('--use-env-proxy') ? process.env : undefined, Agent);
function hasAgentCheckServerIdentity(options) {
let { agent } = options;
if (agent === false)
return false;
if (agent === null || agent === undefined) {
if (typeof options.createConnection === 'function')
return false;
agent = module.exports.globalAgent;
}
return agent?.options?.checkServerIdentity !== undefined;
}
/**
* Makes a request to a secure web server.
* @param {...any} args
@@ -638,6 +671,13 @@ function request(...args) {
ObjectAssign(options, ArrayPrototypeShift(args));
}
if (options.checkServerIdentity !== undefined &&
options.checkServerIdentity !== tls.checkServerIdentity &&
!hasAgentCheckServerIdentity(options)) {
options[kPerRequestCheckServerIdentity] =
++perRequestCheckServerIdentityIndex;
}
options._defaultAgent = module.exports.globalAgent;
ArrayPrototypeUnshift(args, options);