htmx icon indicating copy to clipboard operation
htmx copied to clipboard

`hx-disable` is insufficient without input sanitization

Open mawalu opened this issue 2 years ago • 4 comments

I'm unsure if this is a known issue, but hx-disable can be bypassed if it is used without HTML sanitization. While the docs talk about the importance of escaping user input, I think they don't make this clear enough. The issue becomes even more critical if the hyperscript plugin is used.

I have two example payloads to demonstrate the issue, but I hesitate to share them publicly. Do you have some kind of security contact for issues like this, or should I just dump them here?

mawalu avatar Jun 14 '23 15:06 mawalu

I don’t quiet get it.

You can POST (or method‘) everything to every public listener.

People can also just remove attributes by editing the DOM. Or add them. :)

andryyy avatar Jun 14 '23 15:06 andryyy

Sorry for the confusion. My point is about situations like this

<body hx-disable data-disable-scripting>
  <!-- server side user content here -->
</body>

In this case it is possible to still execute htmx (and if present hyperscript) code as part of the user provided content, even if a strict CSP is present, as long as no HTML sanitization happened on the server.

While this may seem obvious it is not what one might expect after reading this description in the docs

This approach allows you to enjoy the benefits of Locality of Behavior while still providing additional safety if your HTML-escaping discipline fails.

mawalu avatar Jun 14 '23 15:06 mawalu

can you give me an example? it sounds like a bug in the hx-disable logic if this is possible, so let's just fix that.

1cg avatar Jun 15 '23 17:06 1cg

The two example payloads I found are

<meta name="htmx-config" content='{"disableSelector":"[lol-no]"}'>
<div _="on intersection(intersecting) alert(document.location.origin)"></div>    

since HTMX accepts new configuration from within disabled blocks. And

<html lang="en" _="on load alert(2 + document.location.origin)">
</html>

since somehow the disable check fails on html elements.

While writing this I realized that there also exists another issue if the hx-disable attribute isn't set on the <body> element but some child: malicious input can just close the tag:

Setup:

<div hx-disable>
<!-- user input -->
</div>

Payload:

</div><div _="on intersection(intersecting) alert(document.location.origin)">

I think strict HTML escaping hygiene is the only way to prevent these issues and there isn't anything HTMX can do to prevent this.

mawalu avatar Jun 15 '23 18:06 mawalu