Implement web application security: Content Security Policy (CSP), CORS configuration, XSS prevention, CSRF protection, security headers, input validation. Use when user asks to "implement web security", "add CSP", "fix XSS vulnerability", or "harden the application".
From sanpx claudepluginhub javimontano/jm-adk --plugin sovereign-architectThis skill is limited to using the following tools:
agents/cors-validator-agent.mdagents/web-security-implementation-agent.mdagents/xss-csrf-guard-agent.mdevals/evals.jsonexamples/sample-output.mdprompts/use-case-prompts.mdreferences/body-of-knowledge.mdreferences/knowledge-graph.mmdreferences/state-of-the-art.mdImplement defense-in-depth web application security using HTTP headers, input validation, output encoding, and authentication hardening.
"Security is not a feature you bolt on — it's a property of every decision in the development lifecycle. The cheapest vulnerability to fix is the one you never wrote."
npx audit-ci or npm audit --audit-level=high — fix critical/high CVEs first.curl -I https://yourdomain.com — check for missing security headers.npx trufflesecurity/trufflehog --regex --entropy=False .unsafe-inline, unsafe-eval, * wildcards.[HECHO] for confirmed issues, [SUPUESTO] for untested assumptions.Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
default-src 'none':
Content-Security-Policy:
default-src 'none';
script-src 'self' 'nonce-{random}';
style-src 'self' 'nonce-{random}';
img-src 'self' data: https://cdn.yourdomain.com;
font-src 'self';
connect-src 'self' https://api.yourdomain.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
// Express: generate nonce per request
res.locals.nonce = crypto.randomBytes(16).toString('base64');
res.setHeader('Content-Security-Policy', `script-src 'nonce-${res.locals.nonce}'`);
upgrade-insecure-requests to force HTTPS.unsafe-eval — it enables XSS via eval(). Refactor code that requires it.// Express + cors package
const corsOptions = {
origin: (origin, callback) => {
const allowed = ['https://app.yourdomain.com', 'https://admin.yourdomain.com'];
if (!origin || allowed.includes(origin)) callback(null, true);
else callback(new Error('Not allowed by CORS'));
},
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400, // Cache preflight for 24 hours
};
Access-Control-Allow-Credentials: true AND Access-Control-Allow-Origin must be specific domain (not *).Origin header directly without validation — this creates a bypass.&, <, >, ", ' → HTML entitiesJSON.stringify() or a dedicated encoderencodeURIComponent()dangerouslySetInnerHTML with user datav-html with user data[innerHTML] with user data — use DomSanitizerimport DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userHTML, { ALLOWED_TAGS: ['b', 'i', 'em'] });
HttpOnly flag on cookies to prevent JS access.script-src 'nonce-...' is the last line of defense — not the first.Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly; Path=/
SameSite=Strict: cookie not sent on cross-site requests (most secure).SameSite=Lax: cookie sent on top-level GET navigations (good default).// Generate token per session
const csrfToken = crypto.randomBytes(32).toString('hex');
// Include in forms and validate on POST
if (req.body.csrf !== req.session.csrf) throw new Error('CSRF validation failed');
X-Requested-With: XMLHttpRequest prevents form-based CSRF.Origin or Referer header matches expected domain for sensitive mutations.Implement all of the following headers:
# Prevent clickjacking
X-Frame-Options: DENY
# Enable XSS filter in older browsers
X-XSS-Protection: 1; mode=block
# Prevent MIME sniffing
X-Content-Type-Options: nosniff
# Force HTTPS for 2 years
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
# Restrict browser features
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
# CSP (configured in Step 2)
Content-Security-Policy: ...
// Wrong
db.query(`SELECT * FROM users WHERE id = ${userId}`);
// Right
db.query('SELECT * FROM users WHERE id = $1', [userId]);
eval(), Function(), child_process.exec(), vm.runInContext().express-rate-limit or API gateway throttling.npm audit — zero critical/high vulnerabilities.curl -H "Origin: https://evil.com" -I https://yourdomain.com/api — should not return Access-Control-Allow-Origin: https://evil.com.<script>alert(1)</script> in all user inputs — must be encoded or blocked by CSP.| Environment | Approach |
|---|---|
| New app (full control) | Nonce-based strict CSP, no unsafe- directives |
| App with inline scripts (legacy) | Start report-only, migrate to nonces incrementally |
| Third-party heavy (GTM, analytics) | Allowlist specific domains, consider trusted types |
| Marketing site with CMS | Hash-based CSP for CMS-generated scripts |
| Scenario | SameSite | HttpOnly | Secure |
|---|---|---|---|
| Session cookie | Strict | Yes | Yes |
| Auth token | Lax | Yes | Yes |
| Preferences (non-sensitive) | Lax | No | Yes |
| Cross-site OAuth flow | None | Yes | Yes (required when None) |
Access-Control-Allow-Origin: * with credentials — Browsers block this combination, but some misconfigured proxies allow it. Always use specific origins.HttpOnly cookies. If localStorage is required, accept the XSS risk and mitigate via CSP.unsafe-inline in CSP — Defeats 90% of CSP's XSS protection value. Migrate to nonces or hashes.Origin directly. Always validate against an allowlist.Secure flag on cookies in production — Without Secure, session cookies transmit over HTTP, enabling MITM theft.Permissions-Policy — Default allow on geolocation, camera, payment opens unnecessary attack surface. Default-deny all browser features.security-audit-{date}.md — Findings with CVE references and severitymiddleware/security-headers.ts — Security headers middlewaremiddleware/cors.ts — CORS configurationmiddleware/csrf.ts — CSRF protection middlewaredocs/CSP-policy.md — Documented CSP policy with rationaleADR-SEC-001.md — Security architecture decisionsSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.