brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
xss-preventionXSS attack prevention with input sanitization, output encoding, Content Security Policy. Use for user-generated content, rich text editors, web application security, or encountering stored XSS, reflected XSS, DOM manipulation, script injection errors.
Independent GitHub snapshot · Automated classification · Original documentation governs
name: xss-prevention description: "XSS attack prevention with input sanitization, output encoding, Content Security Policy. Use for user-generated content, rich text editors, web application security, or encountering stored XSS, reflected XSS, DOM manipulation, script injection errors."
metadata: keywords: - sanitization - HTML-encoding - DOMPurify - CSP - Content-Security-Policy - rich-text-editor - user-input - escaping - innerHTML - DOM-manipulation - stored-XSS - reflected-XSS - input-validation - output-encoding - trusted-types - XSS-attacks - web-security - user-generated-content - secure-coding - script-injection - DOM-based-XSS
Implement comprehensive Cross-Site Scripting attack prevention through input sanitization, output encoding, Content Security Policy headers, and secure coding practices.
| Type | Vector | Defense |
|---|---|---|
| Reflected | URL parameters | Output encoding |
| Stored | Database content | Input sanitization |
| DOM-based | Client-side JS | Safe DOM APIs |
| Mutation | HTML parser quirks | Strict sanitization |
function encodeHTML(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function encodeForAttribute(str) {
return str.replace(/[^\w.-]/g, char =>
`&#x${char.charCodeAt(0).toString(16)};`
);
}
// Usage in templates
app.get('/profile', (req, res) => {
const username = encodeHTML(req.query.name);
res.send(`<h1>Welcome, ${username}</h1>`);
});
import DOMPurify from 'dompurify';
const config = {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href', 'title'],
ALLOW_DATA_ATTR: false
};
function sanitizeHTML(dirty) {
return DOMPurify.sanitize(dirty, config);
}
// React component
function RichContent({ html }) {
return (
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML(html) }} />
);
}
// Express middleware
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader('Content-Security-Policy', [
"default-src 'self'",
`script-src 'self' 'nonce-${nonce}'`,
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"connect-src 'self' https://api.example.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'"
].join('; '));
next();
});
❌ NEVER do any of the following with user-controlled input — these are XSS sinks and there is no safe way to call them with untrusted data:
element.innerHTML / element.outerHTMLeval()document.write()setTimeout / setInterval as a stringonclick="...")// SAFE — use these instead
element.textContent = userInput; // Escaped automatically
element.setAttribute('data-id', id); // Safe for attributes
document.createTextNode(userInput); // Creates safe text node
The safe patterns above (textContent, attribute escaping via setAttribute,
DOMPurify.sanitize) are the only correct ways to handle user input in the DOM.
function isSafeURL(url) {
try {
const parsed = new URL(url);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
}
// Usage
const href = isSafeURL(userURL) ? userURL : '#';
Different contexts require different encoding approaches:
Always encode output by the specific context where data will be rendered.
See references/python-sanitization.md for:
See references/nodejs-advanced.md for:
✅ DO:
❌ DON'T: