Dom security hardening
Skill KraitDev/skiLL.Md/skills/frontend/dom-security-hardening
skiLL.Md is a structured, open-source collection of reusable, self-contained markdown modules that describe how to perform specific software engineering tasks.
npx -y skills add KraitDev/skiLL.Md --skill dom-security-hardeningAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
When hardening a web application against Cross-Site Scripting (XSS) and injection attacks.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
7.5 KB, as published. Nobody here has run it
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());