RCE in React is most often arbitrary JavaScript execution (XSS) in the browser or true RCE on the server/tooling side (Next.js/Node, build chain). Below are quick wins, code fixes, and a free way to scan your site.
Try a free scan: https://free.pentesttesting.com/
More posts: https://www.pentesttesting.com/blog/
What “RCE” means for React apps
- Client-side: Untrusted content that runs as JS = XSS (can steal tokens, pivot to accounts, trigger supply-chain scripts).
- Server-side/SSR & tooling: Unsafe Node APIs, deserialization, or malicious npm packages can lead to actual RCE on your servers/CI.
1) dangerouslySetInnerHTML
done safely
❌ Vulnerable
export default function Post({ html }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
✅ Fix with sanitization
import DOMPurify from 'dompurify';
export default function Post({ html }) {
const clean = DOMPurify.sanitize(html, { ALLOW_UNKNOWN_PROTOCOLS: false });
return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}
Add a strict CSP (no unsafe-inline
) and prefer component rendering over raw HTML.
Screenshot of the free Website Vulnerability Scanner UI:
Screenshot of the free tools webpage where you can access security assessment tools.
2) Never eval
or new Function
user data
❌ Vulnerable
const result = new Function(`return (${userInput})`)(); // user-controlled!
✅ Safer pattern
// If you must parse, define an explicit schema:
import { z } from "zod";
const Shape = z.object({ theme: z.enum(["dark","light"]) });
const safe = Shape.safeParse(JSON.parse(userInput));
3) Template injection via third-party renderers
❌ Vulnerable
import _ from "lodash";
const html = _.template(userTpl)({ name: req.query.name }); // unsanitized
✅ Fix
const tpl = _.template(STRING_TEMPLATE, { variable: "data", imports: {} });
const safeName = DOMPurify.sanitize(name);
const html = tpl({ name: safeName });
4) Next.js / SSR: don’t expose Node execution
❌ Vulnerable (server side)
// pages/api/run.js
import { exec } from "child_process";
export default (req, res) => {
exec(`grep ${req.query.q} data.txt`, (e, out) => res.send(out)); // injection risk
};
✅ Fix
import { spawn } from "child_process";
export default (req, res) => {
const q = String(req.query.q || "");
const ps = spawn("grep", ["--", q, "data.txt"]); // arg-safe
let out = "";
ps.stdout.on("data", d => (out += d));
ps.on("close", () => res.status(200).send(out));
};
5) Supply-chain hygiene (npm)
- Pin versions, enable lockfiles, and use
npm audit
/npm audit fix
. - Restrict postinstall scripts (
--ignore-scripts
in CI). - Scope permissions for CI tokens & artifacts.
Sample Assessment Report by our free tool to check Website Vulnerability:
Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities.
Defense in depth
-
CSP: no
unsafe-inline
, use nonces/hashes. - Escaping: Prefer React’s automatic escaping; sanitize only when you must.
- AuthN/Z: Token scoping, HttpOnly cookies, SameSite.
- Logs & monitoring: Alert on script errors, 3P script changes, and CSP violations.
Run a quick check (free)
- Visit https://free.pentesttesting.com/
- Enter your site and start the scan.
- Review findings and fix with the patterns above. More articles: https://www.pentesttesting.com/blog/
Managed help & services
- Managed IT Services: https://www.pentesttesting.com/managed-it-services/
- AI Application Cybersecurity: https://www.pentesttesting.com/ai-application-cybersecurity/
- Offer Cybersecurity to Your Clients (White-Label): https://www.pentesttesting.com/offer-cybersecurity-service-to-your-client/
- Newsletter: Subscribe on LinkedIn https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7327563980778995713
Top comments (0)