XSSI Attack in React.js: What It Is and How to Crush It (with Code)

Cross-Site Script Inclusion (XSSI) is a sneaky class of data-leak bugs where an attacker’s page loads your sensitive endpoints as if they were scripts (e.g., via <script src="https://api.example.com/me">). If your API returns JSON that can be interpreted as JavaScript—or if the attacker can exploit JS parsing tricks—private data may leak. In modern SPAs, understanding and stopping an XSSI Attack in React.js is table stakes.

Best 7 Ways to Stop XSSI Attack in React.js

This guide breaks down how XSSI works, why React apps are impacted, and the best 7 engineering patterns (server + client) to block it—complete with Node/Express, NGINX, and React code you can paste into production. Throughout, I’ll reference stronger CORS, SameSite/CSRF patterns, CSP hardening, the protective JSON prefix (aka anti-XSSI prefix), and secure fetch utilities your team can adopt in minutes.

Goal: After this article, your team should be able to identify and stop an XSSI Attack in React.js before it ships.


Quick Primer: Why “Script Inclusion” Leaks Data

  • Browsers historically allow <script src="…"> from other origins.
  • If a sensitive endpoint returns something a JS engine will happily execute (JSONP, or JSON that doubles as valid JS), an attacker might capture that data via clever hooks (e.g., overridden constructors, globals, callbacks).
  • Even if the response is JSON, the interpreter for a <script> tag is JavaScript, not JSON. That mismatch is the root of many XSSI stories.

React itself doesn’t cause XSSI—your API design and headers do. But because React apps often consume JSON APIs with cookies for auth, they’re prime targets if responses aren’t guarded.


TL;DR: The Best 7 Defenses Against an XSSI Attack in React.js

  1. Add an Anti-XSSI JSON Prefix to all JSON responses (e.g., )]}',\n) and strip it in the client before JSON.parse.
  2. Disable JSONP & JavaScript-like responses—return pure JSON and never executable JS for data.
  3. Harden CORS (no * with credentials; tight Access-Control-Allow-Origin; preflight).
  4. Set X-Content-Type-Options: nosniff and correct Content-Type: application/json.
  5. Use SameSite cookies + CSRF tokens for sensitive actions and data.
  6. CSP with strict script-src and no untrusted script hosts; eliminate JSONP endpoints entirely.
  7. Origin/Referer checks for sensitive reads; prefer POST + CSRF for truly private data.

Below are detailed, copy-ready examples.

Screenshot of our free Website Vulnerability Scanner tool page

Screenshot of the free tools webpage where you can access security assessment tools for different vulnerability detection.
Screenshot of the free tools webpage where you can access security assessment tools for different vulnerability detection.

1) Server-Side: Add an Anti-XSSI JSON Prefix

Express middleware to prepend )]}',\n to every JSON response:

// xssi-prefix.js
export function xssiPrefix(req, res, next) {
  const originalJson = res.json.bind(res);
  res.json = function (data) {
    // Always send JSON as text with a safe prefix
    const body = ")]}',\n" + JSON.stringify(data);
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.setHeader('X-Content-Type-Options', 'nosniff');
    return res.send(body);
  };
  next();
}
// app.js
import express from 'express';
import { xssiPrefix } from './xssi-prefix.js';

const app = express();
app.use(xssiPrefix);

app.get('/api/me', (req, res) => {
  res.json({ user: { id: 42, email: '[email protected]' } });
});

app.listen(3000, () => console.log('API running on :3000'));

Why this works: If an attacker includes your JSON endpoint via <script>, the first token )]}', causes a syntax error—so JavaScript won’t execute or leak the object. Your React client simply trims the prefix before parsing.


2) React: Safe JSON Fetch That Strips the Prefix

Create a tiny utility for your app:

// safeFetch.ts
export async function safeJson<T = unknown>(input: RequestInfo, init?: RequestInit): Promise<T> {
  const res = await fetch(input, {
    credentials: 'include', // if you rely on cookies
    mode: 'cors',
    ...init,
    headers: {
      'Accept': 'application/json',
      ...(init?.headers || {})
    }
  });

  const text = await res.text();
  // Strip the anti-XSSI prefix if present
  const sanitized = text.startsWith(")]}',") ? text.replace(/^.\]\}',\s?\n?/, '') : text;

  try {
    return JSON.parse(sanitized) as T;
  } catch (e) {
    throw new Error(`Invalid JSON response from ${res.url}`);
  }
}

Usage in a component:

// Profile.tsx
import { useEffect, useState } from 'react';
import { safeJson } from './safeFetch';

type User = { id: number; email: string; };

export default function Profile() {
  const [user, setUser] = useState<User | null>(null);
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    safeJson<{ user: User }>('/api/me')
      .then(({ user }) => setUser(user))
      .catch((e) => setErr(e.message));
  }, []);

  if (err) return <p role="alert">Error: {err}</p>;
  if (!user) return <p>Loading…</p>;
  return <div><h2>Welcome, {user.email}</h2></div>;
}

This pattern helps you safely consume prefixed responses, a core defense for an XSSI Attack in React.js.


3) Disable JSONP & “Executable JSON”

If you still support JSONP or endpoints returning JavaScript (e.g., application/javascript with data), turn it off:

// express.jsonp callback disabled
app.set('jsonp callback name', null); // or simply never implement JSONP

Policy: All data endpoints must return Content-Type: application/json. No arbitrary JS execution for data.


4) CORS: Strict, Credential-Aware Rules (Server + CDN)

Do this:

  • Only allow known origins.
  • When using cookies (credentials), never use * for Access-Control-Allow-Origin.

Express example:

import cors from 'cors';

const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];

app.use(cors({
  origin(origin, cb) {
    if (!origin) return cb(null, false); // block non-origin contexts
    return cb(null, allowedOrigins.includes(origin));
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token']
}));

NGINX example:

location /api/ {
  if ($http_origin ~* ^https://(app|admin)\.example\.com$ ) {
    add_header Access-Control-Allow-Origin $http_origin always;
    add_header Vary Origin always;
    add_header Access-Control-Allow-Credentials true always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-CSRF-Token" always;
    add_header Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" always;
  }
}

Tight CORS reduces attack surface for an XSSI Attack in React.js by stopping unauthorized cross-origin reads (especially with credentials).


5) X-Content-Type-Options: nosniff + Correct MIME

Always set for JSON endpoints:

res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.setHeader('X-Content-Type-Options', 'nosniff');

This prevents MIME sniffing so browsers don’t treat JSON as script in edge cases.


6) SameSite Cookies + CSRF for Sensitive Reads

Set cookies to SameSite=Lax or Strict, and require a CSRF token for endpoints that return sensitive data (not just state-changing actions).

Cookie (Express + cookie lib):

res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'Lax', // or 'Strict' if UX allows
  path: '/'
});

CSRF token check (server):

// pseudo-middleware
function requireCsrf(req, res, next) {
  const token = req.get('X-CSRF-Token');
  if (!token || token !== req.session.csrfToken) {
    return res.status(403).json({ error: 'CSRF token invalid' });
  }
  next();
}

React fetch with CSRF:

const csrf = localStorage.getItem('csrf'); // or from a meta tag after login

await fetch('/api/private/data', {
  method: 'POST', // prefer POST for sensitive reads, with CSRF
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrf ?? ''
  },
  body: JSON.stringify({ request: 'profile' })
});

This combination blocks common paths used in an XSSI Attack in React.js.


7) CSP: Lock Down Script Sources

CSP header example:

Content-Security-Policy: script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
  • Avoid unsafe-inline (use nonces/hashes if needed).
  • Never allow script loads from untrusted origins.
  • Remove legacy JSONP endpoints so CSP can be strict without breaking apps.

Bonus: Detect JSON Served as JavaScript (Automated Test)

Add a test to ensure endpoints cannot execute as script:

import fetch from 'node-fetch';

test('JSON endpoints not executable as script', async () => {
  const res = await fetch('https://api.example.com/me', {
    headers: { 'Accept': 'application/json' }
  });
  const text = await res.text();

  // Must start with anti-XSSI prefix
  expect(text.startsWith(")]}',")).toBe(true);
  // And content-type must be JSON
  expect(res.headers.get('content-type')).toMatch(/application\/json/);
});

Sample vulnerability report from our free tool to check Website Vulnerability

An example of a vulnerability assessment report generated with our free tool provides insights into possible vulnerabilities.
An example of a vulnerability assessment report generated with our free tool provides insights into possible vulnerabilities.

Developer Checklist (Copy/Paste)

  • JSON prefix ()]}',\n) on all JSON responses
  • Client strips prefix before JSON.parse
  • Content-Type: application/json + X-Content-Type-Options: nosniff
  • CORS: specific origins, credentials: true, no * with cookies
  • Cookies: Secure, HttpOnly, SameSite=Lax/Strict
  • CSRF token for sensitive reads (prefer POST)
  • No JSONP / executable JS data endpoints
  • CSP script-src restricted; no untrusted CDNs

These stop an XSSI Attack in React.js without degrading UX.


Further Reading


Services & Backlinks

Managed IT Services

Need proactive patching, monitoring, and secure cloud baselines? Explore our Managed IT Services for ongoing protection against issues that lead to an XSSI Attack in React.js.
👉 https://www.pentesttesting.com/managed-it-services/

AI Application Cybersecurity

Building LLMs or ML-backed apps? We harden AI pipelines and inference APIs to resist data leaks and XSSI-like abuse patterns.
👉 https://www.pentesttesting.com/ai-application-cybersecurity/

Offer Cybersecurity Service to Your Client

Agencies: white-label penetration testing and app security—deliverables your clients will love.
👉 https://www.pentesttesting.com/offer-cybersecurity-service-to-your-client/

Talk to Us

Questions about an XSSI Attack in React.js in your environment? Get an expert review.
👉 https://www.cybersrely.com/contact-us/


Extra Code Patterns You Can Reuse

Sanitize global JSON parsing in a single place:

// jsonClient.ts
type ParseOptions = { stripPrefix?: boolean };

export async function jsonClient<T>(url: string, init: RequestInit = {}, opts: ParseOptions = { stripPrefix: true }) {
  const res = await fetch(url, { credentials: 'include', ...init });
  const raw = await res.text();
  const body = opts.stripPrefix && raw.startsWith(")]}',") ? raw.slice(5).trimStart() : raw;
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${body.slice(0, 120)}`);
  return JSON.parse(body) as T;
}

Block JSONP at the edge (NGINX):

location ~* \.(jsonp|js)$ {
  return 410; # kill legacy JS data endpoints
}

Origin/Referer check (Express):

const allowed = new Set(['https://app.example.com']);
function checkOrigin(req, res, next) {
  const origin = req.get('Origin') || '';
  const referer = req.get('Referer') || '';
  if ([...allowed].some(a => origin.startsWith(a) || referer.startsWith(a))) return next();
  return res.status(403).json({ error: 'Forbidden' });
}

Final Notes

By applying the 7 patterns above, your team dramatically reduces the chance of a successful XSSI Attack in React.js. Pair these controls with regular scanning and code review to keep regressions from sneaking back in.

If you want a hands-on review or a quick security sprint, reach out via our Contact Us page.


Free Consultation

If you have any questions or need expert assistance, feel free to schedule a Free consultation with one of our security engineers>>

Get a Quote

🔐 Frequently Asked Questions (FAQs)

Find answers to commonly asked questions about XSSI Attack in React.js.

Leave a Comment

Your email address will not be published. Required fields are marked *