On this blog, I try to keep things securely locked down. On the ColdFusion side, I run all user generated content (UGC) through a JSoup sanitizer (though I previously used the OWASP AntiSamy project); and now that I've switched my client side libraries from Hotwire (Turbo and Stimulus) over to HTMX 4 and Alpine.js, I want to make double sure that nothing in the UGC output accidentally triggers HTMX or Alpine.js behaviors.
I say "double sure" because my JSoup cleaner already works with a whitelist of tags and attributes that implicitly block all hx-* (HTMX) and x-* (Alpine) bindings. So, this is more about completeness than it is about any known security threat.
Both HTMX and Alpine.js work by walking the DOM (Document Object Model) tree and attaching JavaScript functionality to declarative attributes. And, both libraries provide a mechanism for excluding a given DOM branch from this traversal:
- HTMX 4 - uses
hx-ignoreto exclude DOM branches. - Alpine.js - uses
x-ignoreto exclude DOM branches.
As such, all I have to do in order to prevent malicious HTMX / Alpine.js invocation is add these attributes wherever I output my user generated content. For example, here's a truncated look at how I now output the list of comments on my blog post detail view:
<cfoutput>
<cfloop array="#comments#" index="comment">
<article class="comment">
<header class="meta">
<span class="author">
#e( comment.member.name )#
</span>
<span class="date">
#dateFormat( comment.createdAt, "mmm d, yyyy" )# at
#timeFormat( comment.createdAt, "h:mm TT" )#
</span>
</header>
<!---
USER GENERATED CONTENT (UGC): this has already been run through
the JSoup sanitizer, so we know it's safe to output. But, as a
hardening measure, prevent HTMX/Alpine bindings as well!
--->
<div hx-ignore x-ignore class="content">
#comment.content#
</div>
</article>
</cfloop>
</cfoutput>
As you can see, the <div> that wraps each user's individual comment has both hx-ignore and x-ignore attributes. This eliminates any chance that a malicious attribute can trigger HTMX or Alpine.js behaviors.
Again, this is basically unnecessary thanks to my JSoup cleaner. But, it safe-guards against any mistakes that I might make in the future; and, it's just a night thought experiment that leads me to a more correct application / page state.
Reader Comments
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →