jQuery 3.5.1 vulnerabilities come down to one narrow but real issue: the regular expression inside jQuery's htmlPrefilter function still let a crafted option element carry executable markup past jQuery's own HTML-parsing safeguards, even after version 3.5.0 had patched a closely related flaw just one release earlier. If a project pulls in jQuery below 3.5.1 and passes any attacker-influenced string into .html(), .append(), .after(), or similar DOM-manipulation methods, that string could still trigger script execution in a victim's browser. Here's what the fix actually changed, and why it still matters years later.
What were the jQuery 3.5.1 vulnerabilities, exactly?
The issue tracked as CVE-2020-11023 affected jQuery versions before 3.5.1. jQuery's htmlPrefilter regex — the internal filter every DOM-manipulation method runs HTML strings through — didn't fully account for markup containing a nested option element. An attacker who controlled part of the HTML string passed to .html(), .append(), .prepend(), .after(), .before(), or .replaceWith() could construct a payload that survived the prefilter and executed as script in the page context. This is a textbook stored or reflected cross-site scripting (XSS) primitive: anywhere user input reaches one of those methods without independent sanitization, an attacker gets code execution in another user's browser session.
Why didn't jQuery 3.5.0 fully close the hole?
jQuery 3.5.0, released a few months earlier, patched a sibling issue — CVE-2020-11022 — in the same htmlPrefilter regex, closing off a related pattern involving style and other elements. The two CVEs are commonly confused because they share a root cause: jQuery's HTML prefilter was a regex-based approximation of a real HTML parser, and regex approximations miss edge cases. The 3.5.0 fix narrowed the attack surface without eliminating it, which is exactly why 3.5.1 shipped so soon after — the jQuery team had already been auditing the same code path and caught the follow-on case. It's a useful reminder that a single point release fixing "an XSS bug" doesn't always mean every variant of that bug is gone.
Does this still matter if you never call .html() with untrusted input?
Often, yes, because the risk usually isn't in code your team wrote directly. jQuery plugins, admin-panel templates, and third-party widgets frequently call .html() or .append() internally with data pulled from query strings, API responses, or user profile fields, and that call is invisible unless someone reads the plugin's source. A project can follow strict input-sanitization discipline in its own code and still ship a vulnerable path through a bundled date picker or rich-text widget built on an old jQuery version. This is also why the vulnerability keeps showing up in dependency scans years after the fix: minified, vendored copies of jQuery get copy-pasted into vendor/ or static/ directories, bypassing normal package-manager updates entirely.
How do you check whether your app still ships a vulnerable jQuery bundle?
Run a software composition analysis pass against the actual files that ship to production, not just package.json. Vendored or minified jQuery copies frequently don't register in a package-lock.json diff, so a scanner needs to fingerprint the JavaScript itself. Safeguard's SCA engine does this by hashing and matching bundled library code against known-version signatures, which catches jQuery copies pulled in through CDNs, static asset folders, or third-party themes that a manifest-only scan would miss entirely. Pair that with a policy that blocks new builds from introducing any jQuery version below 3.5.1 (or, better, below the actively maintained 3.7.x line), and the fix from 2020 stops being a recurring finding.
Why does jQuery still show up in scans a decade after most teams stopped writing new jQuery code?
Because jQuery rarely gets removed from a project once it's added — it gets buried under newer frameworks instead. A React or Vue application built on top of an older admin theme, a WordPress plugin, or a legacy jQuery UI widget will often carry jQuery as a silent dependency that nobody on the current team consciously chose. Package registries also make this worse in a subtle way: many WordPress plugins and legacy CMS themes bundle their own private copy of jQuery rather than relying on the platform's shared version, so a site can be running several different jQuery versions simultaneously across its plugin ecosystem, each with its own patch status. That's part of why version-based dependency scans of large, older codebases so often turn up multiple jQuery versions, some current and some years out of date, in the same asset pipeline.
FAQ
Is jQuery 3.5.1 still safe to use today?
It closed both known htmlPrefilter XSS issues (CVE-2020-11022 and CVE-2020-11023), but jQuery has continued shipping updates since; teams starting fresh should use the current 3.7.x release rather than pinning to 3.5.1 specifically.
What's the difference between CVE-2020-11022 and CVE-2020-11023?
Both are XSS issues in the same htmlPrefilter regex. CVE-2020-11022 was fixed in 3.5.0 and covered one class of crafted markup; CVE-2020-11023 was fixed in 3.5.1 and covered a related case involving option elements that the first patch didn't catch.
Does upgrading from an old jQuery version break plugins?
Sometimes. jQuery 3.x removed several deprecated APIs that older plugins relied on (including some jQuery.browser-style detection and certain event-shorthand methods), so an upgrade from 1.x or 2.x is worth testing against a staging environment before rolling to production, even though the security case for upgrading is strong.