From harness-claude
Block script injection by encoding output, sanitizing HTML, and enforcing Content Security Policy.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:owasp-xss-preventionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Block script injection by encoding output, sanitizing HTML, and enforcing Content Security Policy
Block script injection by encoding output, sanitizing HTML, and enforcing Content Security Policy
innerHTML, dangerouslySetInnerHTML, or evalReact auto-escapes JSX expressions. The main risk is dangerouslySetInnerHTML:
// BAD — direct HTML injection
function Comment({ html }: { html: string }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
// GOOD — sanitize with DOMPurify before rendering
import DOMPurify from 'dompurify';
function Comment({ html }: { html: string }) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'ul', 'li', 'p'],
ALLOWED_ATTR: ['href', 'rel', 'target'],
});
return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}
In Express/NestJS template engines, always use auto-escaping. For raw HTML responses:
import escapeHtml from 'escape-html';
// Escapes <, >, &, ", ' — safe for HTML context
const safeOutput = escapeHtml(userInput);
// For HTML attribute context — additional encoding needed
function encodeAttr(value: string): string {
return value
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
CSP is the strongest browser-level defense. Set via HTTP header (not meta tag):
import helmet from 'helmet';
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-{NONCE}'"], // nonce-based is better than unsafe-inline
styleSrc: ["'self'", "'unsafe-inline'"], // Tailwind requires this (or use nonces)
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'"],
fontSrc: ["'self'", 'https://fonts.gstatic.com'],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
frameAncestors: ["'none'"],
upgradeInsecureRequests: [],
},
})
);
For nonce-based CSP with Next.js or Express:
import crypto from 'crypto';
function cspMiddleware(req: Request, res: Response, next: NextFunction) {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.cspNonce = nonce;
res.setHeader(
'Content-Security-Policy',
`script-src 'self' 'nonce-${nonce}'; object-src 'none';`
);
next();
}
Avoid these JavaScript APIs with user input:
// DANGEROUS SINKS — never pass untrusted data to these
element.innerHTML = userInput; // use textContent instead
document.write(userInput);
eval(userInput);
setTimeout(userInput, 0); // string form of setTimeout
location.href = userInput; // validate URL schema first
element.setAttribute('src', userInput); // validate URL schema
// SAFE alternatives
element.textContent = userInput; // no HTML parsing
element.setAttribute('data-val', userInput); // data attributes are safe
// URL validation before href/src assignment
function isSafeUrl(url: string): boolean {
try {
const parsed = new URL(url, window.location.origin);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
}
Three XSS types:
Defense priority:
DOMPurify server-side (SSR/Node):
import { JSDOM } from 'jsdom';
import createDOMPurify from 'dompurify';
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window as any);
const clean = DOMPurify.sanitize(dirty);
https://owasp.org/www-project-top-ten/
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudePrevents XSS attacks via input sanitization, output encoding, CSP headers, DOMPurify, and safe DOM APIs. Use for user-generated content, rich text editors, comments, and dynamic HTML.
Eliminates XSS by context-aware output encoding and content security policies. Trigger when rendering user content in HTML/DOM or building browser-rendered APIs.
Enforce XSS prevention in React apps: safe JSX binding, sanitizing dangerouslySetInnerHTML with DOMPurify, validating URLs, avoiding SSR concatenation, and escaping preloaded state.