fix(cookies): keep a cookie named __proto__ in getCookies - #5663
fix(cookies): keep a cookie named __proto__ in getCookies#5663luantaraschi wants to merge 1 commit into
Conversation
getCookies built its result on a plain object literal, so assigning the __proto__ key reached the Object.prototype setter instead of creating an own property. The assigned value is a string, so the setter is a no-op and the cookie is dropped from the returned record. Reading that key back also returned Object.prototype, which breaks the documented Record<string, string> contract. Use a null-prototype object, as lib/ already does in six other places.
mcollina
left a comment
There was a problem hiding this comment.
LGTM
(However, I think this is a bad idea. We should throw hard when proto appears).
|
Thanks for the review. I checked the three failing jobs, and none of them exercises this change, which only touches
On
Both preserve keys received from the wire with
A rerun should be enough for this PR. I can rebase if you would prefer a fresh run that way. |
This relates to...
No open issue. Found while reading
lib/web/cookies/.Rationale
getCookies()builds its result on a plain object literal:__proto__is a valid cookie name (it is a token per RFC 6265), but assigning it on a plain object reaches theObject.prototypesetter instead of creating an own property. The setter only accepts an object or null, and the assigned value here is always a string, so it does nothing and the cookie is dropped:The second line is the part that bothered me more than the missing key.
getCookiesis typedRecord<string, string>, so a caller that indexes it by an attacker-influenced name gets an object back where the types promise a string.There is no prototype pollution here: the setter refuses a string, so
Object.prototypeis untouched. The bug is silent data loss plus a broken type contract.Changes
getCookiesnow builds its record with{ __proto__: null }, which is already the pattern used inlib/core/util.js,lib/util/runtime-features.js,lib/web/eventsource/eventsource.jsandlib/web/fetch/formdata.js.The existing tests all use
assert.deepEqual, which does not compare prototypes, so none of them needed changing. All 92 tests undertest/cookie/pass.Features
N/A
Bug Fixes
A cookie named
__proto__is now returned bygetCookies()like any other name.Breaking Changes and Deprecations
The returned object no longer inherits from
Object.prototype, so callingcookies.hasOwnProperty(name)on it stops working.Object.hasOwn(cookies, name)andname in cookiesstill work, as does every form of indexing and iteration.Status