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.
// 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.
# 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.