Preventing XSS with Lodash During Object Traversal

When building dynamic JavaScript applications, handling untrusted user input during object access introduces severe vulnerabilities, most notably Cross-Site Scripting (XSS) and prototype pollution. This article explores how the Lodash utility library secures object traversal against injection attacks, detailing how its internal path resolution mitigates prototype-based exploits and how Lodash string utilities can be integrated to ensure dynamic data is sanitized before reaching the browser DOM.

The Threat Model: Dynamic Traversal and XSS

Cross-Site Scripting often occurs when untrusted input is reflected directly into the document object model (DOM) without adequate escaping. When traversing deeply nested structures, dynamic keys supplied by an attacker can cause unexpected execution flows.

If an attacker manipulates the object path (e.g., targeting __proto__ or constructor.prototype), they can cause prototype pollution. When prototype properties are modified globally, downstream client-side rendering engines often inherit malicious payload attributes—such as onerror handlers or script tags—that execute directly in the browser context, converting a traversal flaw directly into a DOM-based XSS vulnerability.

Prototype Pollution Defenses in Lodash Traversal

Lodash methods such as _.get, _.set, and _.has dynamically access nested properties using string or array path representations. To prevent attackers from polluting the global prototype chain during these operations, modern versions of Lodash implement built-in validation during path parsing:

  1. Path Tokenization and Filtering: When parsing a path string like 'user.__proto__.admin', Lodash uses internal helpers such as castPath to split the target into segments.
  2. Key Blacklisting: During assignment operations (_.set, _.setWith), internal mechanisms strictly restrict keys matching __proto__, prototype, and constructor. If an injected path targets these sensitive properties, Lodash bypasses the assignment or ignores the segment, preventing runtime mutation of base JavaScript prototypes.
  3. Safe Property Reading: When reading properties via _.get, Lodash utilizes an internal baseGet loop that safely checks Object.prototype.hasOwnProperty conventions, ensuring that only intended properties are resolved without triggering side effects from polluted prototype chains.

Sanitizing Injected Strings with _.escape

While methods like _.get prevent path-manipulation attacks, they only extract data safely; they do not automatically sanitize the string value stored at that location. An attacker may inject standard HTML and script tags into the value itself.

To prevent stored or dynamic XSS when rendering retrieved values, Lodash provides _.escape(). This method converts unsafe HTML characters into their corresponding HTML entities:

Secure Pattern: Dynamic Retrieval and Output Sanitization

A robust implementation requires pairing safe property resolution with explicit string sanitization before any DOM interpolation takes place.

import _ from 'lodash';

// Untrusted dynamic inputs
const dynamicPath = userInputPath; // e.g., "profile.bio"
const untrustedData = {
  profile: {
    bio: '<img src=x onerror="alert(\'XSS\')">'
  }
};

// Step 1: Safely traverse the object without prototype pollution
const rawValue = _.get(untrustedData, dynamicPath, '');

// Step 2: Ensure the value is sanitized before insertion into the DOM
const safeHtml = _.isString(rawValue) ? _.escape(rawValue) : '';

// Step 3: Safe rendering
document.getElementById('content').innerHTML = safeHtml;

In this implementation, _.get guarantees that path manipulation cannot alter the prototype chain or crash the application with traversal-related runtime exceptions. Following the retrieval, _.escape neutralizes the executable script tags within the dynamic string payload, successfully disarming the XSS attempt.