LibreChat/packages/api/src/auth/agent.ts

62 lines
2.3 KiB
TypeScript
Raw Normal View History

🛡️ fix: Implement TOCTOU-Safe SSRF Protection for Actions and MCP (#11722) * refactor: better SSRF Protection in Action and Tool Services - Added `createSSRFSafeAgents` function to create HTTP/HTTPS agents that block connections to private/reserved IP addresses, enhancing security against SSRF attacks. - Updated `createActionTool` to accept a `useSSRFProtection` parameter, allowing the use of SSRF-safe agents during tool execution. - Modified `processRequiredActions` and `loadAgentTools` to utilize the new SSRF protection feature based on allowed domains configuration. - Introduced `resolveHostnameSSRF` function to validate resolved IPs against private ranges, preventing potential SSRF vulnerabilities. - Enhanced tests for domain resolution and private IP detection to ensure robust SSRF protection mechanisms are in place. * feat: Implement SSRF protection in MCP connections - Added `createSSRFSafeUndiciConnect` function to provide SSRF-safe DNS lookup options for undici agents. - Updated `MCPConnection`, `MCPConnectionFactory`, and `ConnectionsRepository` to include `useSSRFProtection` parameter, enabling SSRF protection based on server configuration. - Enhanced `MCPManager` and `UserConnectionManager` to utilize SSRF protection when establishing connections. - Updated tests to validate the integration of SSRF protection across various components, ensuring robust security measures are in place. * refactor: WS MCPConnection with SSRF protection and async transport construction - Added `resolveHostnameSSRF` to validate WebSocket hostnames against private IP addresses, enhancing SSRF protection. - Updated `constructTransport` method to be asynchronous, ensuring proper handling of SSRF checks before establishing connections. - Improved error handling for WebSocket transport to prevent connections to potentially unsafe addresses. * test: Enhance ActionRequest tests for SSRF-safe agent passthrough - Added tests to verify that httpAgent and httpsAgent are correctly passed to axios.create when provided in ActionRequest. - Included scenarios to ensure agents are not included when no options are specified. - Enhanced coverage for POST requests to confirm agent passthrough functionality. - Improved overall test robustness for SSRF protection in ActionRequest execution.
2026-02-11 22:09:58 -05:00
import dns from 'node:dns';
import http from 'node:http';
import https from 'node:https';
import type { LookupFunction } from 'node:net';
import { isPrivateIP } from './domain';
/** DNS lookup wrapper that blocks resolution to private/reserved IP addresses */
const ssrfSafeLookup: LookupFunction = (hostname, options, callback) => {
dns.lookup(hostname, options, (err, address, family) => {
if (err) {
callback(err, '', 0);
return;
}
if (typeof address === 'string' && isPrivateIP(address)) {
const ssrfError = Object.assign(
new Error(`SSRF protection: ${hostname} resolved to blocked address ${address}`),
{ code: 'ESSRF' },
) as NodeJS.ErrnoException;
callback(ssrfError, address, family as number);
return;
}
callback(null, address as string, family as number);
});
};
/** Internal agent shape exposing createConnection (exists at runtime but not in TS types) */
type AgentInternal = {
createConnection: (options: Record<string, unknown>, oncreate?: unknown) => unknown;
};
/** Patches an agent instance to inject SSRF-safe DNS lookup at connect time */
function withSSRFProtection<T extends http.Agent>(agent: T): T {
const internal = agent as unknown as AgentInternal;
const origCreate = internal.createConnection.bind(agent);
internal.createConnection = (options: Record<string, unknown>, oncreate?: unknown) => {
options.lookup = ssrfSafeLookup;
return origCreate(options, oncreate);
};
return agent;
}
/**
* Creates HTTP and HTTPS agents that block TCP connections to private/reserved IP addresses.
* Provides TOCTOU-safe SSRF protection by validating the resolved IP at connect time,
* preventing DNS rebinding attacks where a hostname resolves to a public IP during
* pre-validation but to a private IP when the actual connection is made.
*/
export function createSSRFSafeAgents(): { httpAgent: http.Agent; httpsAgent: https.Agent } {
return {
httpAgent: withSSRFProtection(new http.Agent()),
httpsAgent: withSSRFProtection(new https.Agent()),
};
}
/**
* Returns undici-compatible `connect` options with SSRF-safe DNS lookup.
* Pass the result as the `connect` property when constructing an undici `Agent`.
*/
export function createSSRFSafeUndiciConnect(): { lookup: LookupFunction } {
return { lookup: ssrfSafeLookup };
}