HTMX Security: CSRF Token Headers and Untrusted HTML Sanitization
- Last updated
- Prerequisites:
- Cross-Site Request Forgery (CSRF)
- Cross-Site Scripting (XSS)
- htmx
- security
- csrf
- xss
- sanitization
- cors
Read at your depth
The practical view
To protect against CSRF attacks in HTMX, attach your server's CSRF token to all outgoing requests using `hx-headers`: `<body hx-headers='{"X-CSRF-Token": "..."}'>`. For XSS protection, always sanitize or escape user-generated content on the server (using server template auto-escaping) before returning HTML partials, because HTMX will execute `<script>` tags present in swapped HTML.
The same idea in other frameworks
React escapes JSX strings by default to prevent XSS; manual `dangerouslySetInnerHTML` is guarded.Angular `DomSanitizer` automatically sanitizing template bindings.Vue auto-escapes `{{ mustache }}` bindings; `v-html` requires manual sanitization.Server-side template auto-escaping + `hx-headers='{"X-CSRF-Token": "..."}'`.Legacy vs modern
Vulnerable Plain Request vs Secure CSRF Header Injection
Plain requests without CSRF tokens are vulnerable to cross-site forgery; `htmx:configRequest` injects security tokens automatically.
<button hx-post="/delete-account">Delete</button> // ❌ Vulnerable to CSRF attacksdocument.body.addEventListener('htmx:configRequest', (e) => e.detail.headers['X-CSRF-Token'] = token); // ✅ NEWInterview gotchas
Context
Interviewers test your knowledge of HTMX script execution behavior and XSS vectors.
The mechanical answer
Yes. By default, **HTMX evaluates `<script>` tags** present in swapped HTML responses. If a backend endpoint reflects unsanitized user input (e.g. `<script>stealCookie()</script>`), HTMX will execute it. To disable script execution across the entire application, set `htmx.config.allowScriptTags = false`.
Trap
Never rely on the browser's default `innerHTML` script-blocking behavior when using HTMX; HTMX explicitly extracts and runs script tags unless disabled.
Context
Checks knowledge of cross-origin security configurations.
The mechanical answer
Enable the **`selfRequestsOnly`** security configuration: `htmx.config.selfRequestsOnly = true` (default in HTMX 2.x). This restricts HTMX to only dispatching AJAX requests to the exact same origin as the host page, blocking accidental or malicious cross-origin data exfiltration.
Trap
If you legitimately need cross-origin API calls with HTMX, you must configure CORS headers on the remote server and set `selfRequestsOnly = false`.