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

CVE-2026-84368: joi Prototype Pollution Vulnerability

CVE-2026-84368 is a prototype pollution vulnerability in joi JavaScript validator that allows attackers to manipulate Object.prototype through schema configuration. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-84368 Overview

CVE-2026-84368 is a prototype pollution vulnerability [CWE-1321] in the joi JavaScript schema validation library and its predecessor @hapi/joi. The flaw resides in lib/messages.js, where exports.compile() and exports.merge() reuse inherited objects for attacker-controlled language keys. A language key named __proto__ writes properties onto Object.prototype, and a constructor key writes to the Object function's static properties. The vulnerability affects joi from 16.0.0 through 17.13.5 and 18.x prior to 18.2.5, plus @hapi/joi through 17.1.1.

Critical Impact

An application that feeds untrusted input into schema-construction configuration can have Object.prototype polluted, causing every inspected object to take the wrong code path when gating on inherited properties.

Affected Products

  • joi versions 16.0.0 through 17.13.5
  • joi versions 18.0.0 through 18.2.4
  • @hapi/joi through 17.1.1 (no fixed version available)

Discovery Timeline

  • 2026-09-01 - CVE-2026-84368 published to NVD
  • 2026-09-02 - Last updated in NVD database

Technical Details for CVE-2026-84368

Vulnerability Analysis

The joi library provides schema description and data validation for JavaScript applications. The vulnerable code path processes localized error messages supplied through APIs such as messages(), message(), prefs({ messages }), Joi.extend({ messages }), and rule({ message }). When merging a message object, the library initialized target[language] using the expression target[language] || {}, which reads inherited properties from the prototype chain rather than only own properties.

An attacker who controls the message configuration can supply a language key of __proto__ or constructor. The subsequent assignment then writes onto Object.prototype or the Object constructor's static properties instead of the intended target. Once Object.prototype is polluted, every object in the runtime inherits the injected property.

The flaw is not reachable through data that joi validates. Exploitation requires an application to pass untrusted input directly into schema-construction configuration, which is why the attack complexity is high and the impact is limited to integrity.

Root Cause

The root cause is unsafe property initialization on an object without an hasOwnProperty check. The pattern target[language] = target[language] || {} traverses the prototype chain when language is __proto__ or constructor, allowing writes to Object.prototype.

Attack Vector

Exploitation requires application code that forwards untrusted keys into joi schema configuration. A consuming application that later gates control flow on the presence of an inherited property, such as if (obj.isAdmin), will take the wrong branch for every inspected object after pollution.

javascript
// Security patch in lib/messages.js (commit 8d0b808)
// Fix: prevent messages proto injection

Assert(typeof message === 'object' && !Array.isArray(message), 'Invalid message for', code);

const language = code;
// Don't reuse an inherited object, otherwise a language named
// __proto__ or constructor writes on the prototype
const localizedTarget = Object.prototype.hasOwnProperty.call(target, language)
    ? target[language]
    : {};
target[language] = localizedTarget;

for (code in message) {
    const localized = message[code];

    if (code === 'root' || Template.isTemplate(localized)) {
        localizedTarget[code] = localized;
        continue;
    }

    Assert(typeof localized === 'string', 'Invalid message for', code, 'in', language);
    localizedTarget[code] = new Template(localized);
}

Source: GitHub Commit 8d0b808. The patch uses Object.prototype.hasOwnProperty.call(target, language) to ensure that only own properties are reused, preventing writes onto Object.prototype. A parallel fix in the 18.x branch uses Object.hasOwn(target, language) for the same purpose. See GitHub Commit 90d0757.

Detection Methods for CVE-2026-84368

Indicators of Compromise

  • Presence of joi versions 16.0.0 through 17.13.5 or 18.0.0 through 18.2.4 in package.json or package-lock.json.
  • Presence of the deprecated @hapi/joi package at any version through 17.1.1.
  • Application code that passes user-controlled objects into messages(), prefs({ messages }), Joi.extend({ messages }), or rule({ message }).
  • Unexpected properties appearing on Object.prototype at runtime, observable via Object.keys(Object.prototype).

Detection Strategies

  • Run software composition analysis such as npm audit, yarn audit, or Dependabot to flag vulnerable joi and @hapi/joi versions.
  • Perform static analysis on application source code to identify direct assignment of request bodies or query parameters into joi message configuration APIs.
  • Add runtime assertions in test suites that inspect Object.prototype for unexpected own properties after schema construction.

Monitoring Recommendations

  • Log and alert on schema-construction calls that accept externally sourced configuration in production code paths.
  • Monitor CI/CD pipelines for introduction of vulnerable versions during dependency updates.
  • Track advisory feeds for GHSA-6w3j-5fw6-r9vr and correlate with deployed inventory.

How to Mitigate CVE-2026-84368

Immediate Actions Required

  • Upgrade joi to version 17.13.6 on the 17.x branch or 18.2.5 on the 18.x branch.
  • Migrate off the deprecated @hapi/joi package, since no fixed version is available for that namespace.
  • Audit application code and remove any path that passes untrusted input directly into joi message or extension configuration.

Patch Information

The fix is delivered in joi 17.13.6 and 18.2.5 and is implemented in GitHub Pull Request #3138 and GitHub Pull Request #3139. The patched code uses Object.prototype.hasOwnProperty.call() or Object.hasOwn() to reject inherited property names during message merging.

Workarounds

  • Filter incoming configuration objects to strip __proto__ and constructor keys before passing them to joi.
  • Use Object.create(null) when building message configuration objects to avoid a prototype chain entirely.
  • Freeze Object.prototype at application startup using Object.freeze(Object.prototype) to block prototype writes at runtime.
bash
# Upgrade joi to a fixed release
npm install joi@^17.13.6
# or, for the 18.x branch
npm install joi@^18.2.5

# Verify installed version
npm ls joi

# Remove deprecated package (no fix available)
npm uninstall @hapi/joi

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

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

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.