>
I think that's only true if your CSP has the word 'unsafe' or '*' in it.No, that's the subtlety that a lot of people in the thread are missing. I wish OP did a better job of explaining the difference.
Imagine that you screw up and some part of your page assigns injects an attacker-controlled string without encoding properly:
So you have something like this:
<div class="ugc">{{ user_message }}</div>
And the attacker can inject arbitrary HTML/JS, so they do this:
<div class="ugc"><script>fetch('/account', { method: 'DELETE' })</script></div>
If you have CSP enabled with standard settings, the attack won't execute. CSP saves you even if you screwed up that badly.
The problem is that even if you keep the CSP settings secure and you add htmx into your app, the attacker can effectively achieve XSS because htmx's functionality is powerful enough that it's mostly equivalent to having arbitrary JS execution:
<div class="ugc"><span hx-delete="/account" hx-trigger="load"></span></div>
So, without htmx, CSP protects you from mistakenly sanitizing input / encoding output, but with htmx, you lose a lot of the benefit of CSP.