🛡️ Client-Side Security Showcase

DOM Manipulation, Event Injection & Safe Rendering Techniques

← Back to Main

⚠️ Threat 1: DOM Manipulation - innerHTML Vulnerability

Risk Level: CRITICAL
Using innerHTML with user input allows attackers to inject arbitrary HTML and JavaScript code, leading to DOM-based XSS attacks.

Why innerHTML is Dangerous:

❌ Vulnerable Code UNSAFE

// VULNERABLE - DO NOT USE
const userInput = getFromURL();
document.getElementById('output')\n .innerHTML = userInput;

This code directly renders user input as HTML, executing any embedded scripts.

✅ Secure Code SAFE

// SECURE - USE textContent
const userInput = getFromURL();
document.getElementById('output')\n .textContent = userInput;

textContent treats input as plain text, escaping any HTML/JavaScript automatically.

Example Attack Payloads (Safe to View Here):
<img src=x onerror="alert('XSS')">
<svg onload="console.log('hacked')">
<body onload="fetch('/steal-data')">
<script>document.location='http://evil.com'</script>

⚠️ Threat 2: Event Handler Injection

Risk Level: CRITICAL
Dynamically setting event handlers through user-controlled data allows attackers to execute arbitrary code on user interactions.

Attack Vectors:

❌ Vulnerable Event Handler UNSAFE

// VULNERABLE
const userCode = getUserInput();
button.onclick = function() {\n eval(userCode); // EXTREMELY DANGEROUS\n};

This executes arbitrary code when the button is clicked.

✅ Secure Event Handling SAFE

// SECURE
const userData = getUserInput();
button.addEventListener('click', () => {\n // Validate and process data safely\n if (isValidData(userData)) {\n processData(userData);\n }\n});

Event handlers are predefined functions, not user input. Data is validated before processing.

⚠️ Threat 3: Malicious JavaScript Execution

Risk Level: CRITICAL
Using eval(), Function(), or dynamic script injection allows complete compromise of the application.

Dangerous Practices:

❌ Vulnerable: Using eval() UNSAFE

// VULNERABLE - NEVER DO THIS
eval(userExpression);
// Attacker could input:
// "fetch('/steal', {..})"

eval() executes any JavaScript code, giving attackers full access to the application.

⚠️ Warning: This demo will NOT actually show eval() execution for security reasons, but this illustrates the danger.

✅ Secure: Parse & Validate SAFE

// SECURE - Use proper parsers
const result = JSON.parse(userJSON);
// Or use a safe math library
const answer = mathEvaluator(expr);

Use specialized parsers like JSON.parse() or dedicated libraries designed for specific data types.

🛡️ Defense Strategies

Key Defensive Practices:

1. Use textContent Instead of innerHTML

// ✅ GOOD: Safe text insertion
document.getElementById('result').textContent = userInput;

// ❌ BAD: Allows HTML/JS execution
document.getElementById('result').innerHTML = userInput;

// ✅ GOOD: Safe HTML using createElement
const div = document.createElement('div');
div.textContent = userInput;
parent.appendChild(div);

2. HTML Allowlisting

When safe HTML is needed, use a library that only allows specific safe tags and attributes.

// ✅ GOOD: Using DOMPurify library
import DOMPurify from 'dompurify';
const cleanHTML = DOMPurify.sanitize(userHTML, {
  ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
  ALLOWED_ATTR: []
});
document.getElementById('result').innerHTML = cleanHTML;

3. Event Handler Stripping

Remove all event attributes before rendering or use predefined handlers only.

// ✅ GOOD: Remove event handlers
const div = document.createElement('div');
div.textContent = userContent;
// Remove any event attributes
['onclick', 'onload', 'onerror', 'onmouseover']
  .forEach(attr => div.removeAttribute(attr));

// ✅ GOOD: Only use predefined handlers
button.addEventListener('click', () => {
  handleUserData(userData);
});

4. Content Security Policy (CSP)

Use CSP headers to prevent inline script execution and restrict script sources.

// ✅ GOOD: CSP Headers
Content-Security-Policy: 
  default-src 'self'; 
  script-src 'self'; 
  style-src 'self' 'unsafe-inline';
  
// This prevents inline scripts and restricts
// script loading to same-origin only

5. Input Validation

Always validate and sanitize user input before processing.

// ✅ GOOD: Validate input
function isValidEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function processUserInput(input) {
  if (!isValidEmail(input)) {
    console.error('Invalid input');
    return;
  }
  // Process validated input
}

✅ Security Checklist

Completed: 0/6

🎯 Key Takeaways

📋 textContent

Default choice for displaying user text. Safely escapes all HTML.

⚠️ innerHTML Carefully

Only with controlled, trusted content. Always sanitize if from users.

✅ Validation First

Always validate input on both client and server side.

🚫 Never eval()

eval() is equivalent to giving hackers full control. Avoid at all costs.

🎯 Explicit Handlers

Define event handlers in code, never from user data.

🛡️ CSP Headers

Use Content Security Policy to enforce security policies.