Cross-Site Script Inclusion (XSSI) is a sneaky data-leak where an attacker <script>
-loads your API and reads secrets if your endpoint returns executable JavaScript or unsafe JSON. Below is a concise, Symfony-focused guide with copy-paste fixes—perfect for dev readers and teams.
👉 Try our free website security scanner to spot XSSI and other issues.
Also see our blog: Pentest Testing Corp.
How XSSI happens (Symfony example)
Vulnerable: returning executable JS (not JSON). If an attacker includes it, your data becomes a global variable on their page.
// src/Controller/ProfileController.php
#[Route('/api/profile.js', name: 'api_profile_js', methods: ['GET'])]
public function profileAsJs(): Response {
$data = ['email' => 'alice@example.com', 'role' => 'admin'];
// ❌ Executable JavaScript — XSSI-prone
$body = 'window.__profile = ' . json_encode($data) . ';';
return new Response($body, 200, ['Content-Type' => 'application/javascript']);
}
Attacker page:
<script src="https://victim.example.com/api/profile.js"></script>
<script>
// now readable cross-site — data leaked
console.log(window.__profile);
</script>
📸 Screenshot of the Website Vulnerability Scanner tool homepage:
Screenshot of the free tools webpage where you can access security assessment tools.
Safer pattern #1: Strict JSON + anti-XSSI prefix
Return pure JSON (not JS) and add a harmless prefix that breaks execution if included via <script>
.
// src/Controller/ProfileController.php
use Symfony\Component\HttpFoundation\Response;
#[Route('/api/profile', name: 'api_profile', methods: ['GET'])]
public function profile(): Response {
$data = ['email' => 'alice@example.com', 'role' => 'admin'];
$prefix = ")]}',\n"; // breaks script execution; clients strip it before JSON.parse
$json = $prefix . json_encode($data, JSON_UNESCAPED_SLASHES);
return new Response($json, 200, [
'Content-Type' => 'application/json; charset=utf-8',
'X-Content-Type-Options' => 'nosniff',
'Cross-Origin-Resource-Policy' => 'same-site',
]);
}
Client parsing tip:
// strip prefix before JSON.parse
fetch('/api/profile').then(r => r.text()).then(t => {
const clean = t.replace(/^\)\]\}',\n?/, '');
return JSON.parse(clean);
});
Safer pattern #2: Block cross-origin inclusion at the edge
Add security headers globally via an event subscriber.
// src/EventSubscriber/SecurityHeadersSubscriber.php
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
final class SecurityHeadersSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents(): array { return ['kernel.response' => 'onKernelResponse']; }
public function onKernelResponse(ResponseEvent $event): void {
$r = $event->getResponse();
$r->headers->set('X-Content-Type-Options', 'nosniff');
$r->headers->set('Cross-Origin-Resource-Policy', 'same-site');
// Optional: CORP/CORB hardening
$r->headers->set('Content-Type', $r->headers->get('Content-Type') ?: 'application/json; charset=utf-8');
}
}
Safer pattern #3: Avoid GET for sensitive data + CSRF
Return sensitive data via POST and require a CSRF token.
# config/routes.yaml
api_secure_profile:
path: /api/secure/profile
controller: App\Controller\SecureController::profile
methods: [POST]
// src/Controller/SecureController.php
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
public function __construct(private CsrfTokenManagerInterface $csrf) {}
public function profile(Request $req): JsonResponse {
$token = $req->request->get('_token');
if (!$this->csrf->isTokenValid(new CsrfToken('api_profile', $token))) {
return $this->json(['error' => 'invalid_csrf'], 403);
}
return $this->json(['ok' => true]);
}
📸 Sample assessment report from our tool to check Website Vulnerability:
Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities.
Bonus hardening checklist
- Disable JSONP and never return executable JS from APIs.
-
Cookies: use
SameSite=Lax
orStrict
,HttpOnly
,Secure
. -
CORS: only allow trusted origins; avoid
Access-Control-Allow-Origin: *
with credentials. -
CSP on your pages:
script-src 'self'
(reduces risky third-party scripts). - Audit endpoints with our free tool for a website security test.
Services from Pentest Testing Corp.
- Managed IT Services — proactive ops, patching, threat monitoring.
- AI Application Cybersecurity — secure LLMs, prompt injection defenses, model gates.
- Offer Cybersecurity to Your Client — white-label security for agencies/MSPs.
Newsletter: Subscribe on LinkedIn
Read more on our blog → https://www.pentesttesting.com/blog/.
Top comments (0)