Skip to content

Own __proto__ keys are renamed to __proto_ and lose their value on decode #135

Description

@spokodev

Bug

An own __proto__ key does not survive a round-trip — it is silently renamed to __proto_, and its value is lost:

const { encode, decode } = require('cbor-x');

const value = JSON.parse('{"__proto__": 1, "a": 2}'); // own enumerable __proto__
Object.keys(decode(encode(value)));                    // ["__proto_", "a"]  ← key renamed
Object.getOwnPropertyDescriptor(decode(encode(value)), '__proto__'); // undefined

safeKey (in decode.js) rewrites __proto__ to __proto_ to avoid prototype pollution. That avoids pollution, but corrupts the data — the same issue raised for the sibling library in kriszyp/msgpackr#159, where the agreed direction was to use Object.defineProperty so the key becomes a real own property (as JSON.parse/structuredClone do).

Heads-up for the fix

I tried the defineProperty approach locally (a setKeyValue helper at the object[safeKey(key)] = … sites + a computed ["__proto__"] key in the compiled record reader). It fixes every reader path, but a fuzz run surfaced one interaction worth flagging: when a __proto__ value participates in the value-sharing extension (tag 28), the shared-reference path does Object.assign(target, targetProperties) (decode.js ~L1096), and target can end up being the shared value itself (e.g. a Uint8Array), so Object.assign throws Cannot set property length … which has only a getter. So the fix needs to account for that sharing path, not only the key assignment.

I can put together a PR if useful — but since it touches the decode hot path and you've already weighed in on the approach in #159, an issue with the repro and the sharing caveat seemed the better first step.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions