Improper output encoding or escaping

Improper output encoding or escaping

Description

When JavaScript's replace searches for a string, as in $STR.replace('character', 'replacement'), it changes only the first occurrence. Using it to escape potentially dangerous characters can leave later occurrences unchanged, allowing an attacker to bypass the transformation.

Potential impact

  • Script or SQL injection when output retains characters that are significant in its destination context
  • Bypasses of incomplete escaping or filtering

Remediation

  • If every occurrence must be replaced, use a regular expression with the global (g) flag. Do not rely on quote replacement to prevent SQL injection; use parameterized queries for SQL.
  • Use an encoder appropriate to the output context. If HTML markup must be allowed, use a sanitization library such as DOMPurify.
  • For HTML text, encode the required characters, including &, <, >, ", and ', as HTML entities. Do not apply this treatment unchanged to JavaScript, CSS, URLs, or other contexts.

Examples

Before

javascript
function escapeQuotes(s) {
  return s.replace("'", "''");
}

function escapeHtml(html) {
  return html.replace("<", "&lt;").replace(">", "&gt;");
}

After

javascript
function escapeQuotes(s) {
  return s.replace(/'/g, "''"); // Replace every single quote
}

function escapeHtml(html) {
  return html.replace(/[&<>"']/g, (ch) => ({
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#x27;",
  }[ch])); // Encode the characters needed for HTML text
}

Explanation:

  • Before: .replace("character", ...) replaces only the first occurrence. Other characters required by the output context also need appropriate handling.
  • After: Regular expressions with the global (g) flag process every occurrence. The HTML helper encodes the characters needed for HTML text, preventing bypasses caused by repeated characters.

References