koto on X: "jQuery 4.0.0 supports Trusted Types https://t.co/POkrBC0kF2 (thanks, @m_gol 👏👏👏) and this integration exemplifies _why_ Trusted Types can stop DOM XSS in a way other approaches can't. Let me explain (thread)."
jQuery 4.0.0 supports Trusted Types github.com/jquery/jquery/… (thanks, @m_gol 👏👏👏) and this integration exemplifies _why_ Trusted Types can stop DOM XSS in a way other approaches can't. Let me explain (thread).
jQuery 4.0.0 supports Trusted Types github.com/jquery/jquery/… (thanks, @m_gol 👏👏👏) and this integration exemplifies _why_ Trusted Types can stop DOM XSS in a way other approaches can't. Let me explain (thread).
If you ever grepped for .innerHTML to find XSSes, you would quickly learn that jQuery uses that and other DOM XSS sinks a lot through its own many wrappers (.after(), .html(), jQuery(html), ...). That made analyzing code for DOM XSS harder than it already was.
Not only you had to grep for native DOM XSS sinks, but had to also consider all jQuery-specific sinks (there's many. Do you know all of them? Does your security linter?). Since it's DOM XSS you have to also check what _values_ reach those sinks - it's untenable for large apps.
We had XSSes because of these discrepancies. In practice jQuery gets discarded from the analysis as noise, because it is often a "false-positive finding". For example, issues in snyk.io/vuln/npm:jquery are "potential" XSSes, triggering only if you use jQuery in a specific way.
All in all, these issues made it hard to know if your application has XSS, if it was using jQuery. Manual code analysis of every data flow to jQuery sinks doesn't scale, and new jQuery versions can introduce slight changes, or add new sinks.
Additionally, a lot of jQuery sinks, e.g. api.jquery.com/jQuery/ are polymorphic - they analyze the input and try to guess what you wanted. jQuery('.foo') will never reach innerHTML, jQuery('<div><p>') will. Is jQuery(foobar) an XSS then? 🤷 Should you flag it in your app? 🤷♀️
So maybe let's patch jQuery to make it XSS-free? Sometimes it works (we did it for the strict-dynamic gadget).
Imagine you make jQuery sanitize HTML before writing to innerHTML. XSS removed, but you also just broke half of your apps that legitimately passed JS to jQuery.
... and you also didn't patch all of it. There are attribute sinks in jQuery too! $(iframe).attr('srcdoc', boom), and there are URL, or script sinks that don't have anything to do with HTML, but cause XSS nonetheless.
XSS happens because the web platform makes it trivial to introduce. You have to pay special attention not to (Inspect your URLs! Sanitize your HTML! Avoid innerHTML! Escape for the right context! Remember about javascript:!). Some libs do some of these things for you sometimes.
jQuery cannot do those things. As a library, it cannot tell if the input comes from the app author, or from the attacker. It's just some string, and jQuery has to assume the author knew what they were doing calling its functions. If the author made a single mistake - boom!
Now you can force your apps to make that security decision, with a simple trick.
If you pass jQuery an object that quacks like a TrustedHTML, it will assume you want to treat it as an HTML and pass it unmodified to native HTML sinks - and strings are still supported!
How is that fixing XSS?
Add a CSP: require-trusted-types-for 'script' header - that tells your browser to only accept TrustedHTML, and reject strings in innerHTML.
jQuery(cssString) works, jQuery(aTrustedHTML) works, but jQuery(htmlString) throws a CSP violation.
Now, at runtime, you know exactly which specific jQuery calls can actually cause XSSes.
For each, decide if the input comes from the user and needs sanitizing (hint: DOMPurify can produce TrustedHTMLs!), or is fully app-controlled and just needs "blessing" as a TrustedHTML.
Use github.com/google/safeval… for blessing, for example. Important part is, unlike lib, the app knows the data provenance and can make the security decision.
You can also ignore jQuery(aCssSelector), jQuery(anElement) at all, these don't surface in violations, and can't cause XSS.
Before TT, we could not effectively detect DOM XSSes and protect applications using jQuery from that vuln. Finding XSS required analyzing all of the app code, and knowing jQuery internals deeply. Protecting required magic incantations and hoping we covered all the bases.
With TT, the issue is simply:
Use version >= 4.0.0. Add this CSP header. Fix your (usually few, as HTML sinks are rarely used!) violations, we can even rewrite some code automatically for you. You're done. We're done. XSS is gone.
Funny bit is, jQuery lib is not even _using_ Trusted Types to give us that amazing capability. It's what we call "TT agnostic". The only requirement for such libs is not to modify the input data reaching XSS sinks.
Yeah, Trusted Types work even if not used. Magic 🧙