Cross-site scripting through jQuery DOM methods

Cross-site scripting through jQuery DOM methods

Description

Passing user-controlled strings as HTML to jQuery's html(), append(), prepend(), wrap(), wrapInner(), wrapAll(), before() or after() may execute malicious markup. globalEval() executes strings as code, while getScript() fetches and executes a script from a URL; the code and URL need separate trust checks.

Potential impact

  • Malicious scripts may expose accessible cookies or authentication information.
  • An attacker may compromise a session and act with the user's permissions.
  • Injected HTML or JavaScript may deceive users with phishing content.

Remediation

  • Use text() for text and purpose-specific APIs such as val() for form values.
  • Encode text for an HTML body; if actual HTML must be allowed, restrict it with a trusted sanitizer.
  • Do not pass external input to globalEval(). Use only fixed, trusted script URLs with getScript(). HTML escaping cannot secure code execution or validate script URLs.

Examples

Before

javascript
// Pass user input directly to a DOM manipulation method
function vulnerable(userInput) {
  $("#container").html(userInput); // XSS risk
}

// Another example
const hash = window.location.hash;
$("div").append(hash); // Risk depends on the actual value interpreted as HTML

After

javascript
// Use text() to display text
function safe(userInput) {
  $("#container").text(userInput); // Display as text
}

// Alternatively, escape before HTML insertion
function escapeHTML(str) {
  return String(str).replace(/[&<>'"]/g, function (c) {
    return {
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': "&quot;",
      "'": "&#39;",
    }[c];
  });
}

function safeWithEscape(userInput) {
  $("#container").html(escapeHTML(userInput)); // Insert after escaping
}

Explanation:

  • Before: Untrusted values reach APIs that interpret HTML. Current browsers do not percent-decode a URL fragment when it is read, so encoded tags in window.location.hash alone do not establish script execution. Check how the actual HTML value is constructed, including any separate decoding.
  • After: text() or escaping for the HTML body displays values as text at this output location.

References