Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Disable or re-validate redirects on outbound requests to user-influenced hosts
Set redirect: 'manual' (or maxRedirects: 0) on validated outbound fetches and re-apply allowlist/IP checks to each redirect Location before following.
Bad example
| 1 | // Front-door host is validated, but redirects are followed automatically. |
| 2 | if (await isAllowedHost(userUrl)) { |
| 3 | // fetch follows up to 20 redirects by default — the allowed host can 302 |
| 4 | // to http://169.254.169.254/ and the client happily follows it. |
| 5 | const res = await fetch(userUrl); // redirect: 'follow' (default) |
| 6 | return res.text(); |
| 7 | } |
Explanation (EN)
Validating only the initial URL is bypassed when the client auto-follows redirects: a permitted (or attacker-controlled) endpoint returns a 3xx pointing at an internal address, and the validated check never runs again on the new target.
Objašnjenje (HR)
Validacija samo početnog URL-a zaobilazi se kad klijent automatski slijedi redirecte: dopušteni (ili napadačev) endpoint vrati 3xx koji pokazuje na internu adresu, a validacijska provjera se nikad ne izvrši ponovno na novom odredištu.
Good example
| 1 | async function safeFetch(rawUrl: string, maxHops = 3): Promise<Response> { |
| 2 | let current = rawUrl; |
| 3 | for (let hop = 0; hop <= maxHops; hop += 1) { |
| 4 | await assertAllowedAndPublic(current); // allowlist + resolved-IP range check |
| 5 | const res = await fetch(current, { redirect: 'manual' }); |
| 6 | if (res.status < 300 || res.status >= 400) return res; |
| 7 |
|
| 8 | const location = res.headers.get('location'); |
| 9 | if (!location) return res; |
| 10 | current = new URL(location, current).toString(); // resolve relative redirects, loop to re-validate |
| 11 | } |
| 12 | throw new Error('Too many redirects'); |
| 13 | } |
Explanation (EN)
Redirects are handled manually so every hop is re-validated against the same host/IP rules before the next request is made, and a hop cap prevents redirect loops. The protection survives 3xx-based pivots into the internal network.
Objašnjenje (HR)
Redirecti se obrađuju ručno tako da se svaki skok ponovno validira po istim host/IP pravilima prije sljedećeg zahtjeva, a limit skokova sprječava petlje redirecta. Zaštita preživljava 3xx pivote u internu mrežu.
Notes (EN)
axios maxRedirects: 0, got followRedirect: false, and native fetch redirect: 'manual' are the equivalent switches.
Bilješke (HR)
axios maxRedirects: 0, got followRedirect: false i native fetch redirect: 'manual' su ekvivalentni prekidači.
Exceptions / Tradeoffs (EN)
Calls to fixed, fully-trusted first-party upstreams (your own gateway) may follow redirects normally. The manual-validation requirement applies whenever the host is user-influenced or the upstream is third-party.
Iznimke / Tradeoffi (HR)
Pozivi prema fiksnim, potpuno pouzdanim first-party upstreamovima (vlastiti gateway) mogu normalno slijediti redirecte. Zahtjev za ručnom validacijom vrijedi kad god je host pod utjecajem korisnika ili je upstream third-party.