xss-anti-pattern

xss-anti-pattern

Security anti-pattern for Cross-Site Scripting vulnerabilities (CWE-79). Use when generating or reviewing code that renders HTML, handles user input in web pages, uses innerHTML/document.write, or builds dynamic web content. Covers Reflected, Stored, and DOM-based XSS. AI code has 86% XSS failure rate.

2estrelas
1forks
Atualizado 1/22/2026
SKILL.md
readonlyread-only
name
"xss-anti-pattern"
description

"Security anti-pattern for Cross-Site Scripting vulnerabilities (CWE-79). Use when generating or reviewing code that renders HTML, handles user input in web pages, uses innerHTML/document.write, or builds dynamic web content. Covers Reflected, Stored, and DOM-based XSS. AI code has 86% XSS failure rate."

Cross-Site Scripting (XSS) Anti-Pattern

Severity: Critical

Summary

Cross-Site Scripting (XSS) is a type of injection vulnerability where an attacker injects malicious client-side scripts into a web page viewed by other users. This happens when an application includes untrusted data in a web page without proper validation or encoding. XSS attacks can steal session cookies, deface websites, redirect users to malicious sites, or even perform actions on behalf of the victim. It is a pervasive and dangerous vulnerability, with AI-generated code showing a particularly high failure rate in preventing it.

The Anti-Pattern

The anti-pattern is directly embedding user-controlled data into HTML content without context-aware encoding or sanitization.

1. Reflected XSS

Malicious script is reflected immediately in the web browser from user-supplied input.

BAD Code Example

<!-- VULNERABLE: User input is directly inserted into the HTML output. -->
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h1>Search results for: <!-- Query: --><?php echo $_GET['query']; ?><!-- --></h1>
    <p>No results found for your search.</p>
</body>
</html>

<!-- Attacker's request URL:
     http://example.com/search.php?query=<script>alert(document.cookie)</script>

     Resulting HTML in victim's browser:
     <h1>Search results for: <script>alert(document.cookie)</script></h1>
     The script executes, displaying the victim's cookies.
-->

GOOD Code Example

<!-- SECURE: HTML-encode all user input before rendering. -->
<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h1>Search results for: <?php echo htmlspecialchars($_GET['query'], ENT_QUOTES, 'UTF-8'); ?></h1>
    <p>No results found for your search.</p>
</body>
</html>

<!-- Resulting HTML in victim's browser:
     <h1>Search results for: &lt;script&gt;alert(document.cookie)&lt;/script&gt;</h1>
     The script is rendered as harmless text, not executable code.
-->

2. Stored XSS

Malicious script is stored on the server (e.g., in a database) and served to users each time they visit the affected page.

BAD Code Example

# VULNERABLE: User-provided comments are stored and displayed without encoding.
from flask import Flask, request, render_template_string
import sqlite3

app = Flask(__name__)
db = sqlite3.connect('comments.db')
db.execute('CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY, content TEXT)')

@app.route('/post_comment', methods=['POST'])
def post_comment():
    comment = request.form['comment']
    # CRITICAL FLAW: Comment is stored directly, no encoding or sanitization.
    db.execute("INSERT INTO comments (content) VALUES (?)", (comment,))
    db.commit()
    return "Comment posted!"

@app.route('/view_comments')
def view_comments():
    comments = db.execute("SELECT content FROM comments").fetchall()
    html_output = "<h1>Comments</h1>"
    for comment in comments:
        # The stored malicious script is now rendered directly to every visitor.
        html_output += f"<p>{comment[0]}</p>"
    return render_template_string(html_output)

# Attacker posts: <script>alert('You have been hacked!');</script>
# Every user viewing comments will now see the alert.

GOOD Code Example

# SECURE: HTML-encode all data retrieved from the database before rendering.
from flask import Flask, request, render_template_string, escape # Import escape for HTML encoding

app = Flask(__name__)
db = sqlite3.connect('comments_safe.db')
db.execute('CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY, content TEXT)')

@app.route('/post_comment_safe', methods=['POST'])
def post_comment_safe():
    comment = request.form['comment']
    # It's generally best practice to store raw user input and escape on output.
    db.execute("INSERT INTO comments (content) VALUES (?)", (comment,))
    db.commit()
    return "Comment posted safely!"

@app.route('/view_comments_safe')
def view_comments_safe():
    comments = db.execute("SELECT content FROM comments").fetchall()
    html_output = "<h1>Comments</h1>"
    for comment in comments:
        # SECURE: Use `escape` (or `htmlspecialchars` in PHP, or a templating engine's auto-escape)
        # to HTML-encode the data before inserting it into the HTML.
        html_output += f"<p>{escape(comment[0])}</p>"
    return render_template_string(html_output)

# Even better: Use a templating engine (like Jinja2 in Flask) with auto-escaping enabled by default.
# return render_template('comments.html', comments=comments)
# In comments.html: {{ comment.content }} (auto-escaped)

3. DOM-based XSS

The XSS vulnerability resides in client-side code rather than server-side code.

BAD Code Example

// VULNERABLE: Client-side JavaScript directly uses URL parameters in innerHTML.
// http://example.com/page.html?name=<img%20src=x%20onerror=alert(document.cookie)>
window.onload = function() {
    var params = new URLSearchParams(window.location.search);
    var username = params.get('name'); // Gets user input from URL.

    // CRITICAL FLAW: innerHTML interprets the string as HTML, executing the script.
    document.getElementById('welcomeMessage').innerHTML = 'Welcome, ' + username + '!';
};

GOOD Code Example

// SECURE: Use `textContent` which treats input as plain text, not HTML.
window.onload = function() {
    var params = new URLSearchParams(window.location.search);
    var username = params.get('name');

    // SECURE: textContent sets the text content of the node,
    // not parsing it as HTML, preventing script execution.
    document.getElementById('welcomeMessage').textContent = 'Welcome, ' + username + '!';
};

// If you absolutely need to insert HTML from user input, use a robust sanitization library
// like DOMPurify.
// document.getElementById('welcomeMessage').innerHTML = DOMPurify.sanitize(userHtml);

Detection

  • Code Review: Examine any code that takes user input or data from a database and inserts it into an HTML page. Look for:
    • Direct use of echo, print, innerHTML, document.write(), insertAdjacentHTML().
    • Templating engines with auto-escaping disabled.
    • String concatenation to build HTML.
  • Dynamic Analysis (Penetration Testing):
    • Input common XSS payloads (<script>alert(1)</script>, "><img src=x onerror=alert(1)>) into all input fields (URL parameters, form fields, headers).
    • Check if the payloads are reflected or stored and executed.
  • Use XSS Scanners: Automated tools can help identify potential XSS vulnerabilities.

Prevention

  • [ ] HTML-encode all untrusted data before inserting it into HTML content. This is the primary defense against XSS. Use functions like htmlspecialchars (PHP), escape (Python Flask), or templating engine auto-escaping (Jinja2, Handlebars).
  • [ ] Use context-sensitive encoding: Different contexts (HTML body, HTML attribute, JavaScript, URL, CSS) require different encoding schemes. Do not use a generic encoder for all contexts.
  • [ ] Sanitize HTML if necessary: If your application must allow users to provide rich HTML content, use a robust, well-maintained HTML sanitization library (e.g., DOMPurify for JavaScript). Never try to write your own HTML sanitizer.
  • [ ] Use textContent instead of innerHTML when inserting user-provided strings into the DOM via JavaScript.
  • [ ] Implement a strong Content Security Policy (CSP) as a defense-in-depth mechanism. A strict CSP can mitigate XSS by restricting which scripts can execute and from where resources can be loaded.
  • [ ] Perform input validation: While not a primary defense against XSS, validating input to restrict character sets or length can reduce the attack surface.

Related Security Patterns & Anti-Patterns

References

You Might Also Like

Related Skills

coding-agent

coding-agent

179Kdev-codegen

Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.

openclaw avataropenclaw
Obter
add-uint-support

add-uint-support

97Kdev-codegen

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

pytorch avatarpytorch
Obter
at-dispatch-v2

at-dispatch-v2

97Kdev-codegen

Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.

pytorch avatarpytorch
Obter
skill-writer

skill-writer

97Kdev-codegen

Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.

pytorch avatarpytorch
Obter

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

oven-sh avataroven-sh
Obter

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

oven-sh avataroven-sh
Obter