dom-security-hardening
Skill6 starsChanged 6 months agoMITView on GitHub
When hardening a web application against Cross-Site Scripting (XSS) and injection attacks.
In this repository13 other files it gives its agents.
- caching-strategiesSkill
- event-driven-designSkill
- logging-observability-standardsSkill
- api-design-restSkill
- database-query-optimizationSkill
- error-handling-architectureSkill
- code-review-guidelinesSkill
- ci-cd-pipeline-architectureSkill
- debugging-strategiesSkill
- git-workflow-branchingSkill
- react-component-designSkill
- state-management-patternsSkill
- accessibility-ui-designSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 4 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 51
Enforce CSP: Add strict <meta http-equiv="Content-Security-Policy"> tag in HTML <head> (or HTTP headers)
- Distinctive: line 55
Implement Sanitizer: If HTML rendering is REQUIRED, use DOMPurify or equivalent BEFORE insertion
- Distinctive: line 56
Test CSP: Verify policy blocks all unauthorized execution attempts
- Distinctive: line 57
Verify No Bypasses: Use security scanner (OWASP ZAP, Burp) to confirm XSS vectors are closed
- Very specific: line 60
MUST implement strict CSP: default-src 'self'.
- Very specific: line 61
MUST NEVER use inline <script> blocks in HTML
- Very specific: line 62
MUST NEVER use inline style="..." attributes
- Very specific: line 63
MUST NEVER use eval(), setTimeout(string), new Function(string)
- Very specific: line 64
MUST NEVER use innerHTML, outerHTML, or dangerouslySetInnerHTML with user input
- Very specific: line 65
MUST use textContent or innerText for all dynamic text insertions
- Distinctive: line 66
MUST sanitize user HTML with DOMPurify before any insertion
- Very specific: line 67
MUST NOT use 'unsafe-inline' or 'unsafe-eval' in CSP
- Very specific: line 99
JavaScript: All DOM mutations via safe APIs (textContent, className, setAttribute)
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
DOM Security Hardening
Purpose
XSS attacks kill applications. This skill hardens the DOM attack surface by enforcing a strict Content Security Policy, eliminating unsafe DOM APIs, and stripping execution vectors like inline scripts and styles. Following this skill is MANDATORY for any user-facing web application handling user input.
When to use
- Setting up the initial
index.htmlor document root of a web application - Refactoring legacy code that relies on direct DOM manipulation
- Auditing a frontend codebase for XSS vulnerabilities
- Processing rich text or markdown input from untrusted users
- Creating forms or chat systems that accept user input
When NOT to use
- CSS framework design (separate concern)
- React component prop validation (use React Component Design)
- Backend input validation (different layer, still required)
Inputs required
- HTML document structure
- JavaScript files with DOM manipulation
- Understanding of Content Security Policy basics
- Sanitizer library decision (DOMPurify, sanitize-html, etc.)
Workflow
- Enforce CSP: Add strict
<meta http-equiv="Content-Security-Policy">tag in HTML<head>(or HTTP headers) - Externalize Assets: Extract ALL inline
<script>and<style>blocks into separate.jsand.cssfiles - Remove Inline Events: Replace inline
onclick="...",onchange="..."with standardaddEventListenerbindings - Replace Unsafe DOM: Replace
innerHTML,outerHTML,dangerouslySetInnerHTMLwithtextContentorinnerText - Implement Sanitizer: If HTML rendering is REQUIRED, use DOMPurify or equivalent BEFORE insertion
- Test CSP: Verify policy blocks all unauthorized execution attempts
- Verify No Bypasses: Use security scanner (OWASP ZAP, Burp) to confirm XSS vectors are closed
Rules
- MUST implement strict CSP:
default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none' - MUST NEVER use inline
<script>blocks in HTML - MUST NEVER use inline
style="..."attributes - MUST NEVER use
eval(),setTimeout(string),new Function(string) - MUST NEVER use
innerHTML,outerHTML, ordangerouslySetInnerHTMLwith user input - MUST use
textContentorinnerTextfor all dynamic text insertions - MUST sanitize user HTML with DOMPurify before any insertion
- MUST NOT use
'unsafe-inline'or'unsafe-eval'in CSP
Anti-patterns
innerHTMLAssignment:element.innerHTML = userInput(immediate XSS)javascript:URIs:href="javascript:void(0)"orhref="javascript:alert(1)"- Unsafe CSP:
Content-Security-Policy: default-src *; script-src 'unsafe-inline' - Event Handler Strings: Creating event handlers from user input or strings
- Trusting User Input: Assuming any user input is safe to insert into DOM
- Missing Sanitizer: Using rich text editor without sanitizing output
Failure conditions
- CSP header/meta tag is missing
- Inline scripts or styles remain in production code
innerHTMLused with user inputdangerouslySetInnerHTMLused without sanitization- CSP allows
'unsafe-inline'or'unsafe-eval' - Sanitizer library is not installed for rich text rendering
Validation checklist
- CSP header/meta tag present with restrictive policy
- No
<script>tags with inline code (all external) - No inline
style="..."attributes (all CSS classes) - No
onclick,onchange,oninputinline event handlers - All DOM text insertions use
textContentorinnerText - No
innerHTML,outerHTML, ordangerouslySetInnerHTMLwith user input - DOMPurify (or equivalent) used for any rich text rendering
- No
eval(),setTimeout(string),new Function(string)calls - Security scanner passes (no XSS vulnerabilities detected)
- CSP blocks inline script execution (verify in browser console)
Output format
- HTML file: Strict CSP meta tag in
<head>, external<script>tags at end of<body> - JavaScript: All DOM mutations via safe APIs (
textContent,className,setAttribute) - CSS: Separate
.cssfiles, no inline styles anywhere - Rich Text: HTML sanitized via DOMPurify before insertion
- Validation: Automated XSS scan passes
Security considerations
- Threat Model: Prevent XSS attacks via user input injection, DOM gadgets, third-party scripts
- Mitigations: CSP prevents execution, sanitizer prevents HTML injection, safe APIs prevent eval
- Constraints: CSP may conflict with analytics/ads (allow specific domains only)
- Legacy Code: Some frameworks may require CSP relaxation (document trade-offs)
- Third-party Scripts: Load analytics/ads only from trusted CDNs with subresource integrity (SRI)
Agent execution notes
- Agent MAY: Add CSP header, externalize inline scripts/styles, replace innerHTML with textContent, implement DOMPurify
- Agent MUST NEVER: Use
'unsafe-inline'or'unsafe-eval'in CSP, ignore sanitization requirements, leave inline event handlers - Agent MUST ASK: Before adding third-party scripts, before relaxing CSP for legacy code, before using dangerouslySetInnerHTML
- Agent MUST VALIDATE: CSP policy is strict, no inline scripts remain, no unsafe DOM APIs, XSS scanner passes
Example
❌ Anti-pattern (Unsafe XSS vectors, no CSP):
<!-- No CSP -->
<a href="javascript:void(0)" onclick="submitForm()">Click me</a>
<div id="user-bio"></div>
<script>
// Unsafe: direct user input to DOM
document.getElementById('user-bio').innerHTML = getUserInput();
// Unsafe: inline style
document.getElementById('user-bio').setAttribute('style', 'color: red;');
// Unsafe: event handler string
setTimeout("console.log('vulnerable')", 1000);
</script>✅ Correct pattern (Hardened, safe):
<!-- Strict CSP enforced -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; img-src 'self' https:; font-src 'self';"
>
<a href="#" id="submit-btn">Click me</a>
<div id="user-bio"></div>
<!-- External script only -->
<script src="/js/app.js"></script>// app.js
// 1. Safe event binding
document.getElementById('submit-btn').addEventListener('click', (e) => {
e.preventDefault();
submitForm();
});
// 2. Safe text insertion (escapes HTML by default)
document.getElementById('user-bio').textContent = getUserInput();
// 3. Safe styling via CSS classes
document.getElementById('user-bio').classList.add('text-red');
// 4. If HTML rendering is absolutely required, sanitize first
import DOMPurify from 'dompurify';
document.getElementById('user-bio').innerHTML = DOMPurify.sanitize(getUserMarkdown());Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

