Description
This would solve...
undici and native-node>=18-fetch expose (as far as I know, and see documented) no way to protect against SSRF attacks when making server-side calls to arbitrary / user-controllable URLs (that are normally WWW, but could be abused to try to exfiltrate info from an internal network).
In the nodejs ecosystem,
- Non-
fetchlibs likerequestoraxioscan use middleware like ssrf-req-filter. It provides anagent/httpAgent/httpsAgentthat you can pass in these libs secondoptionsargument:
const ssrfFilter = require('ssrf-req-filter');
const url = 'http://169.254.169.254/latest/user-data/iam/security-credentials/' // your choice of sensitive "internal" URL here
axios.get(url, { httpAgent: ssrfFilter(url), httpsAgent: ssrfFilter(url) }) // <-- SSRF "PLUGIN" ADDED HERE
.then((response) => { console.log(`Success', response) });
.catch((error) => { console.log('Error', error); })
- 3rd-party
fetchlibnode-fetchalso supports ssrf-req-filter, though a similaragentAPI:
const ssrfFilter = require('ssrf-req-filter');
const nodefetch = require("node-fetch");
const url = 'http://169.254.169.254/latest/user-data/iam/security-credentials/' // your choice of sensitive "internal" URL here
nodefetch(url, { agent: ssrfFilter(url) }) // <-- SSRF "PLUGIN" ADDED HERE
.then((response) => { console.log(`Success', response) });
.catch((error) => { console.log('Error', error); })
The implementation of such SSRF protection is out of topic, but:
- ssrf-req-filter's "TL;DR" is this line ...
- ... which depends on ipaddr.js categorizing addresses according to various RFCs
Given the above, my question:
In undici / built-in-node>=18 native fetch, I see no trace of supporting such agents with a ({host: string}) => boolean signature letting me decide at runtime to cancel a request.
- Is it actually unsupported, with no plan to support it? If so, what do you (undici/native-node-fetch maintainers) recommend to do to protect against SSRF? To make the SSRF check before calling
fetch? (At the cost of an extra DNS resolution before callingfetch) - Is it unsupported in browser fetch, but potentially coming to server-side node
fetchat some point? - Or is it supported but lacks documentation (or I missed it 😄?)
The implementation should look like...
undici (fetch?) should support setting kind of option letting users plug anti-SSRF logic.
Typically, an agent function of signature {host: string} => boolean (agent is passed an IP, and expected to return a boolean).
I have also considered...
I searched undici's open & closed issues for ssrf, nothing. Grepping for agent yields many things but it looks like there's a naming collision around what is an agent in your context vs. in an axios/request context. They don't seem to have similar responsibilities.
I searched undici's discussions for ssrf, nothing.
I read the options supported by standard fetch in mdn / fetch, nothing in the documented options I could find related to agent / ssrf stuff.
I grepped the fetch WHATWG spec for "SSRF", without success.
Additional context
Related to CVE-2023-28155 / request #3442
Thanks for fetch!