From 3695f912229b504a71a10c79357c47a4f7fc0d16 Mon Sep 17 00:00:00 2001 From: ZeroPath Date: Mon, 6 Jul 2026 16:10:49 +0000 Subject: [PATCH] Pin validated DNS resolution in fetch proxy --- index.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 6b4ab9d..50b445c 100644 --- a/index.js +++ b/index.js @@ -39,21 +39,29 @@ app.get('/fetch', async (req, res) => { return res.status(400).send('URL not allowed'); } try { - // DNS resolution to prevent DNS rebinding - try { + // Resolve once and pin the request to the validated address to avoid DNS rebinding TOCTOU. const addresses = await dns.lookup(parsedUrl.hostname, { all: true }); for (const { address } of addresses) { if (isPrivateIp(address)) { return res.status(400).send('URL not allowed'); } } - } catch (e) { - return res.status(400).send('Invalid hostname'); - } - - const resp = await axios.get(url); + + const [firstAddress] = addresses; + if (!firstAddress || !firstAddress.address) { + return res.status(400).send('Invalid hostname'); + } + + const lookup = (_hostname, _options, callback) => { + callback(null, firstAddress.address, firstAddress.family); + }; + + const resp = await axios.get(url, { + lookup, + maxRedirects: 0, + }); res.send(resp.data); } catch (e) { - res.status(500).send(e.message); + return res.status(400).send(e.message); } }); \ No newline at end of file