XSS Vulnerability Prevention | Blue Frog Docs

XSS Vulnerability Prevention

Diagnose and fix Cross-Site Scripting (XSS) vulnerabilities that allow attackers to inject malicious code into your website

XSS Vulnerability Prevention

What This Means

Cross-Site Scripting (XSS) is a security vulnerability that allows attackers to inject malicious JavaScript code into your web pages. When other users view these pages, the malicious code executes in their browsers, potentially stealing sensitive data, hijacking sessions, or performing unauthorized actions on behalf of the user.

Types of XSS Vulnerabilities

Reflected XSS:

  • Malicious code in URL parameters
  • Immediately reflected back to user
  • Often through search queries or error messages
  • Example: ?search=<script>alert('XSS')</script>

Stored XSS:

  • Malicious code stored in database
  • Executed whenever data is displayed
  • Comments, profiles, messages
  • More dangerous (persistent)

DOM-Based XSS:

  • Client-side JavaScript manipulation
  • Never sent to server
  • Manipulates DOM directly
  • Example: innerHTML, eval(), document.write()

Impact on Your Business

Security Breaches:

  • Session hijacking - attackers steal user sessions
  • Credential theft - steal passwords and sensitive data
  • Account takeover - perform actions as the user
  • Malware distribution - spread viruses to users
  • Defacement - modify page content

Legal & Compliance:

  • GDPR violations (data breach)
  • PCI DSS compliance failures
  • Legal liability
  • Mandatory breach notifications
  • Fines and penalties

Business Impact:

  • Lost customer trust
  • Brand damage
  • Revenue loss
  • Support costs
  • Potential lawsuits
  • Security audit failures

User Impact:

  • Data theft
  • Privacy violations
  • Financial loss
  • Identity theft

How to Diagnose

Method 1: Manual Testing

Test input fields:

  1. Find all user inputs (search, comments, forms)

  2. Enter test payloads:

    <script>alert('XSS')</script>
    <img src=x onerror=alert('XSS')>
    <svg onload=alert('XSS')>
    javascript:alert('XSS')
    "><script>alert('XSS')</script>
    
  3. Submit and check if code executes

What to Look For:

  • Alert boxes appearing
  • Console errors from injected code
  • Unexpected page behavior
  • JavaScript execution

Method 2: Browser DevTools

  1. Open DevTools Console
  2. Enter malicious code in inputs
  3. Check if it appears unescaped in DOM

Check Elements tab:

<!-- Vulnerable - raw script tag in DOM -->
<div class="comment">
  <script>alert('XSS')</script>
</div>

<!-- Safe - escaped -->
<div class="comment">
  &lt;script&gt;alert('XSS')&lt;/script&gt;
</div>

Method 3: Automated Scanners

OWASP ZAP:

  1. Download OWASP ZAP
  2. Configure to scan your site
  3. Run automated scan
  4. Review XSS findings

Burp Suite:

  1. Use Burp Suite Community Edition
  2. Proxy browser through Burp
  3. Use Intruder to test payloads
  4. Check for XSS vulnerabilities

Method 4: Browser Extensions

XSS Strike:

  • Install browser extension
  • Navigate your site
  • Automatically tests for XSS

Wappalyzer:

  • Identifies technologies
  • May indicate vulnerable libraries

Method 5: Code Review

Look for dangerous patterns:

// Vulnerable code examples
element.innerHTML = userInput;
document.write(userInput);
eval(userInput);
new Function(userInput);
element.setAttribute('href', userInput);
window.location = userInput;

General Fixes

Fix 1: Sanitize All User Input

Never trust user input:

// Bad - directly inserting user input
const searchQuery = req.query.search;
res.send(`<h1>Results for: ${searchQuery}</h1>`);

// Good - escape HTML
const escapeHtml = (unsafe) => {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
};

const searchQuery = escapeHtml(req.query.search);
res.send(`<h1>Results for: ${searchQuery}</h1>`);

Use libraries:

// Node.js - use validator
const validator = require('validator');
const clean = validator.escape(userInput);

// Or use DOMPurify (client-side)
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(dirty);

Fix 2: Use Secure DOM Methods

Avoid innerHTML:

// Bad - vulnerable to XSS
element.innerHTML = userInput;

// Good - text content only
element.textContent = userInput;

// Good - create elements safely
const div = document.createElement('div');
div.textContent = userInput;
element.appendChild(div);

React automatically escapes:

// Safe - React escapes by default
function Comment({ text }) {
  return <div>{text}</div>;
}

// Dangerous - explicitly allows HTML
function RichComment({ html }) {
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
  // Only use with trusted, sanitized content!
}

Fix 3: Implement Content Security Policy (CSP)

Add CSP headers:

<!-- Meta tag (basic) -->
<meta http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self' https://trusted.cdn.com">

Server-side (Express.js):

const helmet = require('helmet');

app.use(
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "'unsafe-inline'", "https://trusted.cdn.com"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'", "https://api.example.com"],
      fontSrc: ["'self'", "https://fonts.gstatic.com"],
      objectSrc: ["'none'"],
      upgradeInsecureRequests: []
    }
  })
);

Apache (.htaccess):

<IfModule mod_headers.c>
  Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"
</IfModule>

Nginx:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;

Fix 4: Validate and Sanitize on Server

Server-side validation:

// Express.js example
const express = require('express');
const { body, validationResult } = require('express-validator');

app.post('/comment',
  // Validation
  body('comment')
    .trim()
    .isLength({ min: 1, max: 500 })
    .escape(), // Sanitizes HTML

  (req, res) => {
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const comment = req.body.comment; // Now safe
    // Save to database
  }
);

Don't rely on client-side validation:

// Client-side validation is not enough!
// Always validate on server as well

// Client can easily bypass this
function submitComment(text) {
  if (text.includes('<script>')) {
    alert('Invalid input');
    return;
  }
  // Send to server
}

// Attacker can bypass by sending request directly

Fix 5: Use Parameterized Queries

Prevent SQL injection and XSS:

// Bad - vulnerable to SQL injection AND XSS
const query = `SELECT * FROM comments WHERE id = ${req.params.id}`;
db.query(query, (err, results) => {
  res.send(`<div>${results[0].content}</div>`); // XSS here too!
});

// Good - parameterized query
const query = 'SELECT * FROM comments WHERE id = ?';
db.query(query, [req.params.id], (err, results) => {
  const safeContent = escapeHtml(results[0].content);
  res.send(`<div>${safeContent}</div>`);
});

Fix 6: Set HTTPOnly and Secure Cookies

Prevent cookie theft:

// Express.js
app.use(session({
  secret: 'your-secret-key',
  cookie: {
    httpOnly: true,  // Prevents JavaScript access
    secure: true,    // Only sent over HTTPS
    sameSite: 'strict' // CSRF protection
  }
}));

// Set cookie manually
res.cookie('sessionId', 'abc123', {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  maxAge: 3600000 // 1 hour
});

PHP:

setcookie(
    'sessionId',
    'abc123',
    [
        'expires' => time() + 3600,
        'path' => '/',
        'domain' => 'example.com',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict'
    ]
);

Fix 7: Implement Proper Output Encoding

Context-aware encoding:

// HTML context
function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#x27;");
}

// JavaScript context
function escapeJs(unsafe) {
  return JSON.stringify(unsafe).slice(1, -1);
}

// URL context
function escapeUrl(unsafe) {
  return encodeURIComponent(unsafe);
}

// CSS context
function escapeCss(unsafe) {
  return unsafe.replace(/[^a-zA-Z0-9-_]/g, '\\$&');
}

// Use appropriate encoding
const username = escapeHtml(user.name);
res.send(`<div>Welcome ${username}</div>`);

const userData = escapeJs(JSON.stringify(user));
res.send(`<script>var user = ${userData};</script>`);

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Shopify Shopify XSS Prevention Guide
WordPress WordPress XSS Prevention Guide
Wix Wix XSS Prevention Guide
Squarespace Squarespace XSS Prevention Guide
Webflow Webflow XSS Prevention Guide

Verification

After implementing XSS prevention:

  1. Manual testing:

    • Test all input fields with payloads
    • Verify no script execution
    • Check proper escaping in DOM
  2. Automated scanning:

    • Run OWASP ZAP scan
    • Use Burp Suite
    • Review all findings
  3. Code review:

    • Check for dangerous methods
    • Verify all user input sanitized
    • Ensure output encoding
  4. CSP verification:

    • Check CSP headers present
    • Test policy doesn't break functionality
    • Review CSP violation reports
  5. Penetration testing:

    • Hire security professionals
    • Perform full security audit
    • Test all entry points

Common Mistakes

  1. Only client-side validation - Easily bypassed
  2. Trusting user input - Never trust any input
  3. Using innerHTML - Dangerous method
  4. Weak CSP - Allows 'unsafe-inline'
  5. Not escaping output - Displaying raw user data
  6. Relying on blacklists - Attackers find bypasses
  7. Not testing - Assuming code is safe
  8. Missing HTTPOnly cookies - Sessions can be stolen
  9. Incomplete sanitization - Missing some inputs
  10. Using eval() - Extremely dangerous

XSS Prevention Checklist

  • All user input sanitized
  • Output properly encoded
  • CSP headers implemented
  • HTTPOnly cookies enabled
  • No dangerous DOM methods (innerHTML, eval)
  • Server-side validation
  • Automated security scanning
  • Regular security audits
  • Developer security training
  • Incident response plan

Additional Resources

// SYS.FOOTER