Skip to content
Heist/ feed
Back to feed
HighFix available

@stablelib/cbor: Prototype poisoning via `__proto__` map keys in CBOR decoding

Type: advisorySources: OSV

### 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 source

Published 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"
}