Description
jQuery's html() interprets its input as HTML and inserts it into the DOM. Passing untrusted content directly to it can cause cross-site scripting (XSS): an attacker's markup may execute in another user's browser, enabling session abuse, impersonation or phishing.
Potential impact
- Scripts may steal accessible session cookies or sensitive page data.
- Malicious scripts may run in a user's browser.
- The page may be altered to display deceptive forms or other phishing content.
Remediation
- Use jQuery's
text()instead ofhtml()to display text. - If text must be inserted into an HTML body, escape it for that context. If actual markup must be allowed, restrict tags and attributes with a trusted HTML sanitizer.
- Handle values for their output location. HTML encoding does not replace JavaScript handling or URL validation.
Examples
Before
javascript
// Input is interpreted as HTML
function showMessage(userInput) {
$("#message").html(userInput);
}
// Input such as <script>alert('XSS')</script> can execute a script.
After
The following are separate alternatives. The first displays text directly; the second encodes the string before inserting it into an HTML body.
javascript
// Alternative 1: use text()
function showMessage(userInput) {
$("#message").text(userInput);
}
// Alternative 2: escape for HTML
function escapeHtml(str) {
return str.replace(/[&<>"']/g, function(tag) {
const chars = {'&':'&', '<':'<', '>':'>', '"':'"', "'":'''};
return chars[tag] || tag;
});
}
function showMessage(userInput) {
$("#message").html(escapeHtml(userInput));
}
Explanation:
- Before: Passing input directly to
html()allows supplied markup to be interpreted and scripts to execute. - After:
text()displays the input as text. Alternatively, escaping the input before this HTML insertion prevents it from being interpreted as markup.