GitHub Advisoryadvisory · npm

GHSA-qjx8-664m-686j JavaScript Cookie: Per-instance prototype hijack in assign() enables cookie-attribute injection

HIGH Published 2026-05-21 Modified 2026-06-11 Official page ↗
Aliases
CVE-2026-46625
Ecosystem
npm
Packages
js-cookie
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weaknesses
CWE-1321
Reviewed
2026-05-21

Affected packages

• npm js-cookie: < 3.0.7 → fixed in 3.0.7

Description

Summary `js-cookie`'s internal `assign()` helper copies properties with `for...in` + plain assignment. When the source object is produced by `JSON.parse`, the JSON object's `"__proto__"` member is an *own enumerable* property, so the `for…in` enumerates it and the `target[key] = source[key]` write triggers the `Object.prototype.__proto__` setter on the fresh `target` (`{}`). The result is a per-instance prototype hijack: `Object.prototype` itself is untouched, but the merged `attributes` object now inherits attacker-controlled keys. Because the consuming `set()` function then enumerates the merged object with another `for...in`, every key the attacker placed on the polluted prototype lands in the resulting `Set-Cookie` string as an attribute pair. The attacker can set `domain=`, `secure=`, `samesite=`, `expires=`, and `path=` on cookies whose attributes the developer thought were locked down. Impact Any application that forwards a JSON-derived object as the `attributes` argument to `Cookies.set`, `Cookies.remove`, `Cookies.withAttributes`, or `Cookies.withConverter` is vulnerable. This is the standard pattern when cookie configuration comes from a backend: ```js const cfg = await fetch('/config').then(r => r.json()); Cookies.set('session', token, cfg.cookieAttrs); // cfg.cookieAttrs influenced by attacker ``` A payload of `{"__proto__":{"domain":"evil.example","secure":"false","samesite":"None"}}` causes js-cookie to emit: ``` Set-Cookie: session=TOKEN; path=/; domain=evil.example; secure=false; samesite=None ``` Affected code ```js // src/assign.mjs — full file export default function (target) { for (var i = 1; i Suggested patch ```diff --- a/src/assign.mjs +++ b/src/assign.mjs @@ export default function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] • for (var key in source) { • target[key] = source[key] • } + for (var key in source) { + if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue + Object.defineProperty(target, key, { + value: source[key], + writable: true, + enumerable: true, + configurable: true, + }) + } } return target } ``` Equivalent one-liner alternative - iterate own names only and filter: ```js for (const key of Object.getOwnPropertyNames(source)) { if (key === '__proto__') continue target[key] = source[key] } ```

Related

Alias · CVE (1)

  • CVE-2026-46625 JavaScript Cookie is a JavaScript API for handling cookies, client-side. vulnerability

Weakness · CWE (1)

  • CWE-1321 Improperly Controlled Modification of Object Prototype Attributes weakness

References