Skip to main content
Vulnerability Database/CVE-2026-90771

CVE-2026-90771: joi Library Prototype Pollution Vulnerability

CVE-2026-90771 is a prototype pollution flaw in joi library affecting versions before 17.13.8 and 18.2.9. Attackers can inject __proto__ keys in custom messages to modify object prototypes. This article covers technical details, affected versions, impact assessment, and mitigation strategies.

Published:

CVE-2026-90771 Overview

CVE-2026-90771 is a prototype pollution vulnerability [CWE-1321] in the joi schema validation library for JavaScript. The flaw affects joi versions before 17.13.8 and 18.2.9. The message compilation function accepts __proto__ as an error code key. Attackers who control custom message input can replace the returned object's prototype. This breaks downstream logic that depends on Object.prototype methods and can enable further exploitation paths in applications consuming attacker-influenced schemas.

Critical Impact

Successful exploitation pollutes the prototype of validation message objects, corrupting application behavior that relies on inherited Object.prototype methods and potentially enabling secondary attacks in downstream code.

Affected Products

  • joi versions prior to 17.13.8
  • joi versions prior to 18.2.9
  • Node.js applications using joi schema validation with attacker-influenced custom messages

Discovery Timeline

  • 2026-09-13 - CVE-2026-90771 published to NVD
  • 2026-09-16 - Last updated in NVD database

Technical Details for CVE-2026-90771

Vulnerability Analysis

The vulnerability resides in lib/messages.js inside the message compilation routine. joi allows callers to supply custom error messages as a plain-object map from error code to message template or string. When compiling this map, the library assigned entries directly to the target object without validating the key name. Assigning to the __proto__ key on a plain object invokes the legacy accessor and replaces the target's prototype instead of creating an own property.

Applications commonly pass user-derived or configuration-derived data into validation options. When such data reaches the messages compilation path, an attacker-controlled __proto__ entry rewrites the prototype of the resulting messages object. Downstream code that iterates keys, invokes hasOwnProperty, or performs standard object operations may then throw, return incorrect results, or behave in ways the developer did not anticipate.

Root Cause

The root cause is missing key validation during property assignment on a plain object. The code path used target[code] = message where code originated from untrusted input. JavaScript's legacy __proto__ accessor on Object.prototype intercepts such assignments and mutates the object's prototype chain rather than adding an own property, satisfying the definition of prototype pollution under [CWE-1321].

Attack Vector

Exploitation requires an attacker to influence the messages option or a nested messages object passed to joi validation. This is realistic where applications merge user input into validation configuration, load message overrides from untrusted files, or accept schema definitions from external sources. The attack complexity is elevated because attacker-controlled data must reach the compilation function.

javascript
// Patch from lib/messages.js - reject __proto__ as a message code
if (code === 'root' ||
    Template.isTemplate(message)) {

    // A flat code named __proto__ triggers the legacy accessor on plain-object
    // assignment, replacing target's own prototype instead of creating an own property

    assert(code !== '__proto__', 'Cannot use __proto__ as a message code');

    target[code] = message;
    continue;
}

if (typeof message === 'string') {

    assert(code !== '__proto__', 'Cannot use __proto__ as a message code');

    target[code] = new Template(message);
    continue;
}

Source: GitHub Joi Commit #5b8333c

The patch adds explicit assert checks that reject __proto__ as a message code before assignment, preventing the legacy accessor from mutating the prototype.

Detection Methods for CVE-2026-90771

Indicators of Compromise

  • Application logs showing unexpected TypeError or hasOwnProperty is not a function exceptions after validation calls.
  • HTTP requests or configuration payloads containing __proto__ keys directed at endpoints that pass data into joi validation options.
  • Dependency manifests (package.json, package-lock.json, yarn.lock) referencing joi at versions below 17.13.8 or below 18.2.9.

Detection Strategies

  • Scan source repositories and running dependency trees for vulnerable joi versions using software composition analysis tooling.
  • Inspect code paths that pass user-controlled or externally sourced data into the messages option of Joi.object().validate() or Joi.any().messages().
  • Add runtime logging around message compilation to flag any __proto__ key encountered in validation options.

Monitoring Recommendations

  • Alert on inbound request payloads that contain __proto__, constructor.prototype, or prototype keys, particularly in JSON bodies.
  • Monitor Node.js process error rates and stack traces referencing lib/messages.js in the joi module.

How to Mitigate CVE-2026-90771

Immediate Actions Required

  • Upgrade joi to version 17.13.8 on the 17.x branch or 18.2.9 on the 18.x branch.
  • Audit application code for locations where untrusted input flows into the messages option of joi schemas.
  • Reject or strip __proto__, constructor, and prototype keys from any JSON payload deserialized before it reaches validation logic.

Patch Information

The fix is committed to the hapijs/joi repository in commit 5b8333c9177e08b4ef4ed02903c2d657084e7afb. It adds assert(code !== '__proto__', ...) guards in lib/messages.js before assigning message entries. See the VulnCheck Advisory for Joi and GitHub Joi Issue #3150 for full details.

Workarounds

  • Deep-clone and filter any external message maps to remove __proto__ before passing them to joi.
  • Freeze Object.prototype with Object.freeze(Object.prototype) at process start to block prototype mutation, after validating compatibility with all dependencies.
  • Wrap validation calls in try/catch and reject input that produces unexpected prototype-related exceptions.
bash
# Upgrade joi to a patched release
npm install joi@^17.13.8   # 17.x branch
# or
npm install joi@^18.2.9    # 18.x branch

# Verify installed version
npm ls joi

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.