Chapter 31 · Security Best Practices
Subchapter 31.4
references/javascript-jquery-web-frontend-security.mdMarkdown33 KBView on GitHub
This document is designed as a security spec that supports:
Also bundled
OpenAIIt is intentionally written as a set of normative requirements (“MUST/SHOULD/MAY”) plus audit rules (what bad patterns look like, how to detect them, and how to fix/mitigate them).
MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).
MUST treat the browser as an attacker-controlled environment:
MUST NOT “fix” security by disabling protections (e.g., relaxing CSP to allow unsafe-inline, enabling JSONP “because it works”, adding broad CORS, disabling sanitization, suppressing security checks).
MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.
MUST treat uncertainty honestly: if a protection might exist at the edge (CDN/WAF/reverse proxy headers like CSP), report it as “not visible in repo; verify at runtime/config”.
When asked to write new jQuery code or modify existing jQuery code:
While working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):
When the user asks to “scan”, “audit”, or “hunt for vulns”:
Recommended audit order:
.html, .append, $("<…>"), .load, etc.).dataType:"script", $.getScript, dynamic <script> insertion.href, src, style, on* attributes).$.extend patterns).Examples include:
Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).
Data from third-party APIs or services.
Browser-controlled sources:
location.href, location.search, location.hashdocument.URL, document.baseURI, document.referrerwindow.namelocalStorage / sessionStoragepostMessage event data (unless strict origin and schema validation exists)A sink is a code path where untrusted input can become interpreted as executable code or HTML.
Key jQuery sink categories:
HTML insertion / parsing:
.html(), .append(), and related methods (see CVE notes below). (NVD (opens in a new tab))$(htmlString) (when the argument can be interpreted as HTML markup).jQuery.parseHTML(html, …, keepScripts) especially with keepScripts=true. (jQuery API (opens in a new tab)).load(url) (loads HTML into DOM; has special script execution behavior). (jQuery API (opens in a new tab))Script execution / dynamic code loading:
$.getScript() / $.ajax({ dataType: "script" }) (executes fetched JavaScript). (jQuery API (opens in a new tab))dataType: "jsonp" or implicit JSONP behavior) (executes remote JavaScript as a response). (jQuery API (opens in a new tab))eval, new Function, setTimeout("…"), setInterval("…"), $.globalEval (if present)Dangerous attribute assignment:
href, src, srcdoc, style, or event-handler attributes (onload, onclick, etc.)javascript: URLs are particularly dangerous and discouraged. (MDN Web Docs (opens in a new tab))For each issue found, output:
This is the smallest “production baseline” that prevents common jQuery-related security failures.
MUST load jQuery only from:
If loading from a CDN, SHOULD use SRI (integrity) and correct crossorigin settings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from jquery.com (opens in a new tab))
script-src restrictions and avoiding unsafe-inline). If not done through HTTP server, this can be done through the <meta http-equiv="Content-Security-Policy" content="..."> tag. (OWASP Cheat Sheet Series (opens in a new tab)) NOTE: It is most important to set the CSP’s script-src. All other directives are not as important and can generally be excluded for the ease of development.require-trusted-types-for, then code MUST route DOM-injection through Trusted Types policies. (MDN Web Docs (opens in a new tab))require-trusted-types-for. (blog.jquery.com (opens in a new tab))Even though these are typically set server-side, they materially reduce the blast radius of jQuery-related mistakes. However if the context is only the frontend web application, these cannot be acted on.
X-Content-Type-Options: nosniff, clickjacking protection via frame-ancestors / X-Frame-Options, Referrer-Policy). (OWASP Cheat Sheet Series (opens in a new tab))localStorage) unless the threat model explicitly accepts “XSS == account takeover”. This is not jQuery-specific, but jQuery-heavy DOM manipulation increases the chance of DOM XSS regressions; reduce the payoff.Each rule contains: required practice, insecure patterns, detection hints, and remediation.
Severity: Medium (High if internet-facing app AND version is known-vulnerable)
NOTE: Before performing an upgrade, get concent from the user and try to understand if they have reasons to keep it back. Upgrading can break applications in unexpected ways. Report and recommend upgrades rather than just performing them.
Required:
MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.
MUST upgrade past:
Insecure patterns:
jquery-1.*, jquery-2.*, jquery-3.3.*, jquery-3.4.*, jquery-3.4.1, etc.).Detection hints:
jquery- and parse version strings.package.json, package-lock.json, yarn.lock, pnpm-lock.yaml.vendor/, public/, static/, assets/, wwwroot/ for jquery*.js.Fix:
Notes:
Severity: High
Required:
integrity) and correct crossorigin handling. (jquery.com (opens in a new tab))Insecure patterns:
<script src="https://…/jquery.min.js"></script> with no integrity.Detection hints:
<script src= and check for integrity= + crossorigin=.Fix:
Note: If unable to get the correct SRI tag, skip this step but tell the user. If you end up using the wrong one the app will not function. In that case remove it and inform the user.
Severity: High (if attacker-controlled content reaches these sinks)
Required:
MUST treat any HTML string insertion as a code execution boundary.
MUST use safe alternatives for untrusted text:
.text(untrusted) (text, not HTML). (jQuery API (opens in a new tab)).val(untrusted) for form fields. (jQuery API (opens in a new tab))Insecure patterns (examples):
$(selector).html(untrusted)$(selector).append(untrusted)$(selector).before(untrusted) / .after(untrusted) / .replaceWith(untrusted) / .wrap(untrusted) (and similar)"<div>" + untrusted + "</div>" then passing to jQueryDetection hints:
.html(, .append(, .prepend(, .before(, .after(, .replaceWith(, .wrap(, .wrapAll(, .wrapInner(Fix:
Replace with .text() / .val() or node construction:
const $el = $("<span>").text(untrusted); container.append($el);If the output must contain limited markup, see JQ-XSS-002 (sanitization).
Notes:
Severity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)
Required:
MUST NOT “roll your own” HTML sanitizer with regexes.
If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.
SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. (OWASP Cheat Sheet Series (opens in a new tab))
Insecure patterns:
<script>” or “escape <” attempts followed by .html() insertion.Detection hints:
</> patterns, or “allow all tags” configs..html() or equivalent sinks.Fix:
False positive notes:
Severity: High (if attacker-controlled)
Required:
$() when they might be interpreted as HTML.jQuery.parseHTML(html, …, keepScripts) as a high-risk primitive; keepScripts MUST be false for any untrusted input. (jQuery API (opens in a new tab))Insecure patterns:
const $node = $(untrusted);$.parseHTML(untrusted, /* context */, true) (scripts preserved)Detection hints:
$( calls where the argument is not a static selector or static markup.$.parseHTML( and inspect the keepScripts argument.Fix:
.text() for untrusted values.Severity: Medium (High if URL/content is attacker-controlled)
Required:
MUST NOT use .load() with attacker-controlled URLs or attacker-controlled HTML fragments.
MUST understand jQuery .load() script behavior:
.html() before scripts are removed, which can execute scripts. (jQuery API (opens in a new tab))SHOULD prefer fetch()/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.
Insecure patterns:
$("#target").load(untrustedUrl)$("#target").load("/path?param=" + untrusted)Detection hints:
.load( across JS/TS files.Fix:
Replace .load() with:
fetch() to retrieve JSON, then render via .text() / node construction, orfetch() to retrieve HTML, sanitize it, then inject.If .load() must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.
Severity: High
Required:
MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.
MUST treat these as code execution primitives:
$.getScript(url) executes the fetched script in the global context. (jQuery API (opens in a new tab))$.ajax({ dataType: "script" }) and other script-typed requests that execute responses.SHOULD remove these patterns unless there is a strong, reviewed justification.
Insecure patterns:
$.getScript(untrustedUrl)$.ajax({ url: untrustedUrl, dataType: "script" })<script src=...> injection where src is derived from untrusted input.Detection hints:
getScript(, dataType: "script", globalEval, eval, new Function.Fix:
Severity: Medium (High if attacker can influence URL/endpoint)
Required:
$.ajax, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend setting jsonp: false “for security reasons” if you don’t trust the target. (jQuery API (opens in a new tab))dataType: "json") and explicit origin allowlists server-side.Insecure patterns:
dataType: "jsonp"callback=? or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors.$.get(untrustedUrl) without pinning dataType and disabling JSONP (risk depends on options and jQuery behavior)Detection hints:
jsonp, dataType: "jsonp", callback=?.Fix:
Use JSON over HTTPS with CORS configured server-side.
Set:
dataType: "json"jsonp: false (defense in depth when URL might be ambiguous) (jQuery API (opens in a new tab))Severity: High
NOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.
Required:
Insecure patterns:
$.post("/transfer", {...}) or $.ajax({ method: "POST", ... }) with cookie auth and no CSRF token/header.X-Requested-With (defense-in-depth only, not primary).Detection hints:
Fix:
$.ajaxSetup({ headers: { "X-CSRF-Token": token } }), and ensure server verifies.False positive notes:
Severity: Low (High for events like onclick)
Required:
href, src, action, etc.javascript: URLs are discouraged because they can execute code. (MDN Web Docs (opens in a new tab))onclick, onerror, etc.) from strings.style attributes; prefer toggling predefined CSS classes.Insecure patterns:
$("a").attr("href", untrustedUrl)$("img").attr("src", untrustedUrl)$(el).attr("style", untrustedCss)$(el).attr("onclick", untrustedJs)Detection hints:
.attr("href", .attr("src", .attr("style", .prop("href", .prop("src".Fix:
new URL(value, location.origin) and allowlist protocols (https: etc.) and hostnames when needed.style strings with addClass/removeClass using predefined class names.Severity: Medium (can become High if it enables wrong-element selection in security-relevant UI)
Required:
jQuery.escapeSelector() (available in jQuery 3.0+). (jQuery API (opens in a new tab))Insecure patterns:
$("#" + untrustedId)$("[data-id='" + untrusted + "']") (especially without strict quoting/escaping)Detection hints:
"#" +, ". " +, or template strings used inside $( selectors.Fix:
$("#" + $.escapeSelector(untrustedId)) (jQuery API (opens in a new tab))Notes:
Severity: Medium
Required:
$.extend(true, …)) attacker-controlled objects into application objects without filtering dangerous keys.Insecure patterns:
$.extend(true, target, untrustedObj)$.extend(true, {}, defaults, untrustedObj) where untrustedObj comes from URL/JSON/storageDetection hints:
$.extend(true and inspect sources of merged objects.Fix:
Prefer:
__proto__, prototype, constructor, and nested occurrences.Keep jQuery patched.
Severity: Medium
Required:
require-trusted-types-for), MUST ensure DOM injection goes through Trusted Types policies. (MDN Web Docs (opens in a new tab))Insecure patterns:
script-src 'unsafe-inline' / 'unsafe-eval') without a compensating plan.Detection hints:
Fix:
script-src.When actively scanning, use these high-signal patterns:
jQuery version / sourcing:
jquery-*.js in vendor/ or static/package.json dependency jquery pinned to old versionsintegrity/crossorigin (jquery.com (opens in a new tab))HTML injection sinks (DOM XSS):
.html(, .append(, .prepend(, .before(, .after(, .replaceWith(, .wrap($( where argument might be HTML / template strings$.parseHTML( especially with keepScripts=true (jQuery API (opens in a new tab)).load( (and whether selector is appended; script behavior differs) (jQuery API (opens in a new tab))Script execution / dynamic code:
$.getScript(, dataType: "script" (jQuery API (opens in a new tab))dataType: "jsonp" or jsonp: usage; callback=? patterns (jQuery API (opens in a new tab))eval, new Function, setTimeout("…"), $.globalEvalDangerous attribute writes:
.attr("href", …), .attr("src", …), .attr("style", …)javascript:-like schemes or suspicious URL construction (MDN Web Docs (opens in a new tab))Selector construction:
$("#" + user) and similar; fix via $.escapeSelector (jQuery API (opens in a new tab))Prototype pollution:
$.extend(true, …, userObj); ensure jQuery >= 3.4.0 and filter dangerous keys (NVD (opens in a new tab))CSRF posture for AJAX:
$.post( / $.ajax({ method: ... }) with cookies and no CSRF token/header (OWASP Cheat Sheet Series (opens in a new tab))Defense-in-depth:
Always try to confirm:
Primary jQuery project documentation and release notes:
https://blog.jquery.com/2026/01/17/jquery-4-0-0/. (blog.jquery.com (opens in a new tab))https://jquery.com/download/. (jquery.com (opens in a new tab)).html(): https://api.jquery.com/html/. (jQuery API (opens in a new tab)).text(): https://api.jquery.com/text/. (jQuery API (opens in a new tab)).append(): https://api.jquery.com/append/. (jQuery API (opens in a new tab)).load() (script execution behavior): https://api.jquery.com/load/. (jQuery API (opens in a new tab))jQuery.parseHTML(…, keepScripts): https://api.jquery.com/jQuery.parseHTML/. (jQuery API (opens in a new tab))$.ajax() (jsonp: false security note): https://api.jquery.com/jQuery.ajax/. (jQuery API (opens in a new tab))$.getScript() (executes script): https://api.jquery.com/jQuery.getScript/. (jQuery API (opens in a new tab))jQuery.escapeSelector(): https://api.jquery.com/jQuery.escapeSelector/. (jQuery API (opens in a new tab))jQuery vulnerabilities / advisories:
https://nvd.nist.gov/vuln/detail/CVE-2019-11358. (NVD (opens in a new tab))https://nvd.nist.gov/vuln/detail/CVE-2020-11022. (NVD (opens in a new tab))<option>; patched in 3.5.0): https://nvd.nist.gov/vuln/detail/CVE-2020-11023. (NVD (opens in a new tab))https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2. (GitHub (opens in a new tab))OWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html. (OWASP Cheat Sheet Series (opens in a new tab))https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html. (OWASP Cheat Sheet Series (opens in a new tab))https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html. (OWASP Cheat Sheet Series (opens in a new tab))https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html. (OWASP Cheat Sheet Series (opens in a new tab))https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html. (OWASP Cheat Sheet Series (opens in a new tab))Browser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):
https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity. (MDN Web Docs (opens in a new tab))https://www.w3.org/TR/sri-2/. (W3C (opens in a new tab))https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP. (MDN Web Docs (opens in a new tab))require-trusted-types-for directive: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for. (MDN Web Docs (opens in a new tab))https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API. (MDN Web Docs (opens in a new tab))https://www.w3.org/TR/trusted-types/. (W3C (opens in a new tab))javascript: URL scheme warning: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript. (MDN Web Docs (opens in a new tab))https://github.com/cure53/DOMPurify. (GitHub (opens in a new tab))This file