@stablelib/cbor: Prototype poisoning via `__proto__` map keys in CBOR decoding
### Summary `@stablelib/cbor` decodes CBOR maps into ordinary JavaScript objects and assigns attacker-controlled keys directly onto those objects. A CBOR map key named `__proto__` therefore changes the prototype of the decoded object instead of becoming an ordinary data property. ### Details The decoder builds map results with a plain `{}` and then stores attacker-controlled keys using bracket assignment. That is unsafe for special property names. In JavaScript, assigning to `obj["__proto__"]` on a normal object does not create a plain own property. It invokes the built-in `__proto__` setter and replaces the object’s prototype if the supplied value is an object or `null`. As a result, a CBOR payload containing a map entry like: * key: `"__proto__"` * value: `{ isAdmin: true }` does not decode to an object with an own property called `__proto__`. It decodes to an object whose prototype is now attacker-controlled. Any code that later reads properties through normal lookup will see inherited attacker-supplied values. ### PoC ```js import { decode } from "@stablelib/cbor"; // CBOR: // { // "__proto__": { "isAdmin": true } // } // // a1 map(1) // 69 text(9) // "__proto__" // a1 map(1) // 67 text(7) // "isAdmin" // f5 true const payload = new Uint8Array([ 0xa1, 0x69, 0x5f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x5f, 0xa1, 0x67, 0x69, 0x73, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0xf5 ]); const obj = decode(payload); console.log(Object.hasOwn(obj, "isAdmin")); // false console.log(obj.isA
- Products
- @stablelib/cbor
- Affected versions
- Not specified
- Fixed versions
- 2.0.3
- CVEs
- CVE-2026-106448
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 28 Oct 2026, 03:50 UTC · Revision 1
Source evidence
@stablelib/cbor: Prototype poisoning via `__proto__` map keys in CBOR decoding
core-osv · Original sourcePublished 4 Apr 2026, 04:24 UTC
### Summary `@stablelib/cbor` decodes CBOR maps into ordinary JavaScript objects and assigns attacker-controlled keys directly onto those objects. A CBOR map key named `__proto__` therefore changes the prototype of the decoded object instead of becoming an ordinary data property. ### Details The decoder builds map results with a plain `{}` and then stores attacker-controlled keys using bracket assignment. That is unsafe for special property names. In JavaScript, assigning to `obj["__proto__"]` on a normal object does not create a plain own property. It invokes the built-in `__proto__` setter and replaces the object’s prototype if the supplied value is an object or `null`. As a result, a CBOR payload containing a map entry like: * key: `"__proto__"` * value: `{ isAdmin: true }` does not decode to an object with an own property called `__proto__`. It decodes to an object whose prototype is now attacker-controlled. Any code that later reads properties through normal lookup will see inherited attacker-supplied values. ### PoC ```js import { decode } from "@stablelib/cbor"; // CBOR: // { // "__proto__": { "isAdmin": true } // } // // a1 map(1) // 69 text(9) // "__proto__" // a1 map(1) // 67 text(7) // "isAdmin" // f5 true const payload = new Uint8Array([ 0xa1, 0x69, 0x5f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x5f, 0xa1, 0x67, 0x69, 0x73, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0xf5 ]); const obj = decode(payload); console.log(Object.hasOwn(obj, "isAdmin")); // false console.log(obj.isA
osv:GHSA-w48f-fwg7-ww6p
@stablelib/cbor
Fixed versions: 2.0.3
Complete source record
{
"id": "9d39ac5b259c00b0c61d43f52cdfeac69f2dda470583f95d1395f4ffa0edba93",
"url": "https://osv.dev/vulnerability/GHSA-w48f-fwg7-ww6p",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "@stablelib/cbor: Prototype poisoning via `__proto__` map keys in CBOR decoding",
"summary": "### Summary `@stablelib/cbor` decodes CBOR maps into ordinary JavaScript objects and assigns attacker-controlled keys directly onto those objects. A CBOR map key named `__proto__` therefore changes the prototype of the decoded object instead of becoming an ordinary data property. ### Details The decoder builds map results with a plain `{}` and then stores attacker-controlled keys using bracket assignment. That is unsafe for special property names. In JavaScript, assigning to `obj[\"__proto__\"]` on a normal object does not create a plain own property. It invokes the built-in `__proto__` setter and replaces the object’s prototype if the supplied value is an object or `null`. As a result, a CBOR payload containing a map entry like: * key: `\"__proto__\"` * value: `{ isAdmin: true }` does not decode to an object with an own property called `__proto__`. It decodes to an object whose prototype is now attacker-controlled. Any code that later reads properties through normal lookup will see inherited attacker-supplied values. ### PoC ```js import { decode } from \"@stablelib/cbor\"; // CBOR: // { // \"__proto__\": { \"isAdmin\": true } // } // // a1 map(1) // 69 text(9) // \"__proto__\" // a1 map(1) // 67 text(7) // \"isAdmin\" // f5 true const payload = new Uint8Array([ 0xa1, 0x69, 0x5f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x5f, 0xa1, 0x67, 0x69, 0x73, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0xf5 ]); const obj = decode(payload); console.log(Object.hasOwn(obj, \"isAdmin\")); // false console.log(obj.isA",
"evidence": "osv:GHSA-w48f-fwg7-ww6p",
"products": [
{
"name": {
"value": "@stablelib/cbor",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "2.0.3",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": []
}
],
"severity": "high",
"structured": {
"id": "GHSA-w48f-fwg7-ww6p",
"aliases": [
"CVE-2026-106448",
"GHSA-w48f-fwg7-ww6p"
],
"metrics": [
{
"type": "CVSS_V4",
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N"
}
],
"affected": [
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.3"
}
]
}
],
"package": {
"name": "@stablelib/cbor",
"purl": "pkg:npm/%40stablelib/cbor",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-w48f-fwg7-ww6p/GHSA-w48f-fwg7-ww6p.json"
}
}
],
"modified": "2026-10-07T10:56:10.181649137Z",
"provider": "osv",
"references": [
"https://github.com/StableLib/stablelib/security/advisories/GHSA-w48f-fwg7-ww6p",
"https://github.com/StableLib/stablelib/commit/0f153a63b7552a0e8721f640984113e419015026",
"https://github.com/StableLib/stablelib"
],
"provider_metadata": {
"cwe_ids": [
"CWE-1321"
],
"severity": "HIGH",
"github_reviewed": true,
"nvd_published_at": null,
"github_reviewed_at": "2026-04-04T04:24:27Z"
}
},
"related_cves": [
{
"value": "CVE-2026-106448",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/database_specific/severity"
},
"source_id": "core-osv",
"document_id": 94945,
"published_at": "2026-04-04T04:24:27+00:00"
}