GHSA-r3r9-wp5j-pq5g: High severity npm/request-filtering-agent vulnerability
Summary RequestFilteringHttpAgent / RequestFilteringHttpsAgent block requests to private IPs, but the blocking happens via a synchronous throw inside createConnection() for literal private-IP hostnames (e.g. 169.254.169.254, 127.0.0.1). Node.js's http.request / http.get expects createConnection to emit an error asynchronously; a synchronous throw instead escapes the caller's req.on('error', ...) handler entirely and becomes an unhandled exception that crashes the process.
Affected request-filtering-agent <= 3.2.0 (latest).
PoC (replicated live on 3.2.0) js const http = require('http'); const { RequestFilteringHttpAgent } = require('request-filtering-agent'); const agent = new RequestFilteringHttpAgent(); process.on('uncaughtException', e => { console.log('CRASH:', e.message); // fires — process dies }); const req = http.get({ hostname: '169.254.169.254', port: 80, agent }); req.on('error', e => { / never reached for literal IPs / }); Actual output: request-filtering-agent@3.2.0 synchronous throw escaping error event: UNCAUGHT EXCEPTION (process crash): DNS lookup 169.254.169.254(...) is not allowed. Because, It is private IP address. CRASH CONFIRMED: createConnection throws sync, bypasses req.on("error") Note: hostnames that resolve to private IPs (e.g. localhost) are handled via the async lookup path and correctly emit an error event — this asymmetry confirms the sync-throw is a defect.
Impact Any application using request-filtering-agent where an attacker can trigger an HTTP request to a literal private-IP (e.g. from a user-supplied URL that is pre-validated but still reaches http.get) will crash the Node.js process — full DoS.
Fix Instead of throwing synchronously in createConnection(), call callback(error) (the Node.js net.createConnection error-callback convention) or use process.nextTick(() => socket.destroy(error)) on the returned socket to emit the error asynchronously, allowing req.on('error') to handle it.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/request-filtering-agentto a version that resolves this vulnerability.Fixed in 3.2.1 - Compensating control
Modify request-filtering-agent's createConnection() so literal private-IP blocking reports errors asynchronously: call callback(error), or use process.nextTick(() => socket.destroy(error)) on the returned socket, instead of throwing synchronously.
Event History
Frequently Asked Questions
Who can trigger the process crash?
An unauthenticated remote attacker can trigger it if they can cause an application using the agent to make an HTTP request to a literal private-IP hostname, such as 169.254.169.254 or 127.0.0.1.
Are error handlers on the request sufficient to prevent the crash?
No. For literal private-IP hostnames, the agent throws synchronously from createConnection(), so the exception escapes req.on('error', ...) rather than being delivered as a request error event.
Which versions are affected and what update is available?
request-filtering-agent versions through 3.2.0 are affected. Version 3.2.1 is available in the referenced release.
What can be done if updating is not immediately possible?
Prevent untrusted input from controlling request destinations, particularly literal private IP addresses. Callers also need to account for the synchronous exception path, since relying only on the request error event does not handle it.