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.

Server-Side Request Forgery (SSRF) in React.js

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

Screenshot of the free tools webpage where you can access security assessment tools.
Screenshot of the free tools webpage where you can access security assessment tools.

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.
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

Popular posts from this blog

Fix Sensitive Data Exposure in Symfony Apps

Fix Security Misconfiguration Issues in Symfony

Open Redirect Vulnerability in Symfony