Server-Side Request Forgery (SSRF) in React.js
SSRF isn’t a React bug—it’s a back-end flaw your React app can accidentally trigger. When a front-end sends a URL to an API that then fetches it server-side, attackers can pivot that API to read internal services, cloud metadata, or files.
Read more security posts: https://www.pentesttesting.com/blog/
How React Front-Ends Accidentally Cause SSRF
React UIs often have features like “Preview URL”, “Import from RSS”, or “Fetch webhook status”. If the server blindly fetches user-supplied URLs, it might access http://169.254.169.254/
(cloud creds), http://localhost:2375/
(Docker), or internal hosts like http://intranet-db:5432
.
Vulnerable Pattern (React + Node)
React component (sends any URL to the API):
// Danger: lets users request any URL via your server
export default function Preview() {
const [url, setUrl] = React.useState("");
const [data, setData] = React.useState("");
const go = async () => {
const res = await fetch("/api/fetch?url=" + encodeURIComponent(url));
setData(await res.text());
};
return (<div>
<input value={url} onChange={e=>setUrl(e.target.value)} placeholder="https://example.com/feed" />
<button onClick={go}>Preview</button>
<pre>{data}</pre>
</div>);
}
Express API (vulnerable server-side fetch):
// Danger: no validation, can hit internal/metadata/localhost
app.get("/api/fetch", async (req, res) => {
const target = req.query.url;
const r = await fetch(target);
res.status(200).send(await r.text());
});
Safer Server Controls (Allowlist + Parsing + Timeouts)
import {URL} from "url";
import dns from "dns/promises";
import http from "http"; import https from "https";
const ALLOWED_HOSTS = new Set(["example.com","api.example.com"]);
const BLOCK_CIDRS = ["127.0.0.0/8","10.0.0.0/8","172.16.0.0/12","192.168.0.0/16","::1","fc00::/7"];
function isPrivate(ip){ /* implement CIDR check or use ip-cidr */ return false; }
app.get("/api/fetch", async (req, res) => {
try {
const u = new URL(String(req.query.url || ""));
if (!["http:","https:"].includes(u.protocol)) throw new Error("Protocol not allowed");
if (!ALLOWED_HOSTS.has(u.hostname)) throw new Error("Host not allowed");
const addrs = await dns.lookup(u.hostname, {all:true, verbatim:true});
if (addrs.some(a => isPrivate(a.address))) throw new Error("Private IP blocked");
const controller = new AbortController();
const t = setTimeout(()=>controller.abort(), 5000);
const r = await fetch(u.toString(), {
redirect: "error", // no open redirects
signal: controller.signal,
dispatcher: u.protocol==="http:"?new http.Agent({keepAlive:false}):new https.Agent({keepAlive:false})
});
clearTimeout(t);
if (!r.ok) return res.status(502).send("Upstream error");
res.type("text/plain").send(await r.text());
} catch (e) {
res.status(400).send("Blocked: " + e.message);
}
});
Key ideas: strict allowlist, block private/loopback/metadata ranges, reject non-HTTP(S), disable redirects, add DNS re-resolution, timeouts, and size limits.
Quick Checklist
-
⛔ Don’t fetch arbitrary user URLs. Prefer server-owned integrations.
-
✅ Use allowlists; validate scheme/host/port; re-resolve DNS.
-
✅ Block RFC1918/loopback/metadata IPs and unusual ports.
-
✅ Enforce
redirect: "error"
, timeouts and response size caps. -
✅ Log attempted SSRF for detection.
Try It Free on Your Site
Run a quick external scan while you harden your code:
Screenshot of the Website Vulnerability Scanner to show where to start a scan
Sample vulnerability report generated by the tool to check Website Vulnerability
![]() |
Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities. |
Managed & Partner Services
Managed IT Services
Stability + security for your stack. Learn more: https://www.pentesttesting.com/managed-it-services/
AI Application Cybersecurity
Threat-model LLM apps, secure prompt flows, protect model APIs:
https://www.pentesttesting.com/ai-application-cybersecurity/
Offer Cybersecurity to Your Clients
Agencies/MSPs: white-label audits & testing:
https://www.pentesttesting.com/offer-cybersecurity-service-to-your-client/
Stay Updated
Subscribe on LinkedIn https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7327563980778995713
Pro tip: Even with perfect React code, SSRF is a server concern—treat user-provided URLs as hostile and gate every network hop.
Comments
Post a Comment