CVE-2026-59952

CVE-2026-59952 is a medium-severity security vulnerability in valibot (npm), affecting versions <= 1.4.1. It is fixed in 1.4.2.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

Valibot: record() issue paths can make flatten() throw for inherited Object property names

valibot 1.4.1 can throw a TypeError inside its flatten() helper when validation issues contain attacker-controlled object keys such as toString, valueOf, or hasOwnProperty.

The issue is reachable through normal record() validation. record() intentionally filters __proto__, prototype, and constructor, but it still accepts other own keys that collide with inherited Object.prototype properties. If the record key schema or value schema rejects such an entry, Valibot creates an issue path containing that key. Passing the resulting issues to Valibot's documented flatten() helper causes flatErrors.nested[dotPath] to resolve to the inherited method instead of an own error array, and the helper calls .push(...) on that function.

This is not a global prototype pollution issue. The impact is availability/error handling: applications that validate user-controlled objects with record() and flatten validation errors for API responses can crash the request path with a TypeError instead of returning structured validation errors.

Affected package

  • Ecosystem: npm
  • Package: valibot
  • Affected version verified: 1.4.1
  • Fixed version: none known
  • Repository: open-circle/valibot
  • Current main ref tested by source review: 9bb6617

Root cause

record() uses _isValidObjectKey() before validating record entries. The helper blocks the three classic prototype pollution keys:

key !== '__proto__' &&
key !== 'prototype' &&
key !== 'constructor'

It does not block other inherited Object.prototype names such as toString, valueOf, and hasOwnProperty. These remain valid own JSON object keys and can appear in issue paths when either the record key schema or value schema rejects the entry.

flatten() then creates nested error storage with an ordinary object:

flatErrors.nested = {};

For a dot path such as toString, this check reads the inherited Object.prototype.toString function:

if (flatErrors.nested![dotPath]) {
  flatErrors.nested![dotPath]!.push(issue.message);
}

Because the inherited function is truthy, flatten() calls .push(...) on a function and throws TypeError: flatErrors.nested[dotPath].push is not a function.

Local reproduction

Run in a disposable directory:

npm install [email protected]
node poc_record_flatten_inherited_key_dos.mjs

Minimal example:

import * as v from 'valibot';

const schema = v.record(v.string(), v.number());
const input = JSON.parse('{"toString":"not-a-number"}');

const result = v.safeParse(schema, input);
console.log(result.success); // false
console.log(result.issues[0].path.map((item) => item.key)); // ["toString"]

v.flatten(result.issues); // TypeError

Observed output from [email protected]:

{
  "name": "record value schema rejects attacker-controlled value",
  "key": "toString",
  "success": false,
  "issueCount": 1,
  "firstPath": ["toString"],
  "firstMessage": "Invalid type: Expected number but received \"not-a-number\"",
  "flattened": {
    "ok": false,
    "exception": "TypeError",
    "message": "flatErrors.nested[dotPath].push is not a function"
  }
}

The local PoC also reproduces the same exception for valueOf, hasOwnProperty, isPrototypeOf, propertyIsEnumerable, and toLocaleString. A control case with an ordinary key produces normal flattened errors.

Duplicate checks performed before submission

  • npm metadata confirmed current valibot release is 1.4.1 and maps to open-circle/valibot.
  • gh api repos/open-circle/valibot/private-vulnerability-reporting returned {"enabled":true}.
  • npm audit for a clean project containing only [email protected] returned no vulnerabilities.
  • Repository advisories and the GitHub Advisory Database only returned the historical emoji ReDoS advisory fixed in 1.2.0.
  • OSV exact-version query for npm valibot 1.4.1 returned no vulnerabilities.
  • Public issue/PR searches for flatten toString, flatten hasOwnProperty, record toString, __proto__, constructor, and prototype pollution did not find a matching disclosure of this record() issue-path / flatten() exception.
  • Reviewed related public PRs: open-circle/valibot#67 added prototype pollution mitigation for record() by blacklisting __proto__, prototype, and constructor; it does not cover flatten() collisions with other inherited property names. open-circle/valibot#1429 is an open plain-object / record() type semantics PR and does not disclose this flatten() exception behavior.

Suggested remediation

Use null-prototype containers for flat error maps and/or perform own-property checks before appending:

  • Initialize flatErrors.nested as Object.create(null).
  • Check nested entries with Object.prototype.hasOwnProperty.call(flatErrors.nested, dotPath) rather than truthiness.
  • Consider filtering or escaping unsafe dot path segments in getDotPath() / flatten(), including inherited Object property names.
  • Add regression tests for flatten() with paths toString, valueOf, hasOwnProperty, __proto__, prototype, and constructor.
  • Consider using the same hardening for other accumulator objects that store attacker-controlled keys.

Impact

A remote attacker can trigger this if an application:

  1. validates attacker-controlled JSON objects with v.record(...);
  2. receives an invalid key or invalid value under a key such as toString;
  3. uses Valibot's flatten(result.issues) helper to prepare validation errors.

This is a common pattern in API/form validation: safeParse() collects issues and flatten() converts them into response-friendly error objects. Instead of a validation response, the request can hit an unexpected exception path.

The same root cause can also affect manually constructed issues or other schemas that place inherited Object property names into dot paths. I am reporting the record() path because it uses only public Valibot APIs and attacker-controlled JSON keys.

Affected versions

valibot (<= 1.4.1)

Security releases

valibot → 1.4.2 (npm)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Upgrade valibot to 1.4.2 or later to resolve this vulnerability.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently Asked Questions

  1. What is CVE-2026-59952? CVE-2026-59952 is a medium-severity security vulnerability in valibot (npm), affecting versions <= 1.4.1. It is fixed in 1.4.2.
  2. Which versions of valibot are affected by CVE-2026-59952? valibot (npm) versions <= 1.4.1 is affected.
  3. Is there a fix for CVE-2026-59952? Yes. CVE-2026-59952 is fixed in 1.4.2. Upgrade to this version or later.
  4. Is CVE-2026-59952 exploitable, and should I be worried? Whether CVE-2026-59952 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether CVE-2026-59952 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix CVE-2026-59952? Upgrade valibot to 1.4.2 or later.

Other vulnerabilities in valibot

Stop the waste.
Protect your environment with Kodem.