CodeQL documentation

Unsafe HTML constructed from library input

ID: js/html-constructed-from-input
Kind: path-problem
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-079
   - external/cwe/cwe-116
Query suites:
   - javascript-code-scanning.qls
   - javascript-security-extended.qls
   - javascript-security-and-quality.qls

Click to see the query in the CodeQL repository

When a library function dynamically constructs HTML in a potentially unsafe way, then it’s important to document to clients of the library that the function should only be used with trusted inputs. If the function is not documented as being potentially unsafe, then a client may inadvertently use inputs containing unsafe HTML fragments, and thereby leave the client vulnerable to cross-site scripting attacks.

Recommendation

Document all library functions that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended.

Example

The following example has a library function that renders a boldface name by writing to the innerHTML property of an element.

module.exports = function showBoldName(name) {
  document.getElementById('name').innerHTML = "<b>" + name + "</b>";
}

This library function, however, does not escape unsafe HTML, and a client that calls the function with user-supplied input may be vulnerable to cross-site scripting attacks.

The library could either document that this function should not be used with unsafe inputs, or use safe APIs such as innerText.

module.exports = function showBoldName(name) {
  const bold = document.createElement('b');
  bold.innerText = name;
  document.getElementById('name').appendChild(bold);
}

Alternatively, a HTML sanitizer can be used to remove unsafe content.

const striptags = require('striptags');
module.exports = function showBoldName(name) {
  document.getElementById('name').innerHTML = "<b>" + striptags(name) + "</b>";
}

References