Prototype Pollution
Description
This affects all versions of package immer.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Immer prior to 8.0.1 is vulnerable to prototype pollution via crafted patch operations, allowing attackers to inject properties into Object.prototype.
Vulnerability
Immer, a popular JavaScript library for immutable state management, is susceptible to a prototype pollution vulnerability in all versions before 8.0.1 [1][2]. The bug resides in the applyPatches function, which does not sufficiently sanitize special path elements like __proto__, prototype, or constructor when applying patches to objects [1][3]. An attacker can craft a patch with a path such as ["__proto__", "polluted"], causing the library to modify Object.prototype and pollute all objects in the runtime [1][4].
Exploitation
To exploit this issue, an attacker needs to control the patches passed to applyPatches. This is possible in applications that accept patch data from untrusted sources, such as collaborative editing environments or real-time sync features [2][4]. The attack requires no authentication beyond the ability to supply crafted patch objects. By providing a patch operation with the "add" op and a path traversing __proto__ or prototype, the attacker can inject arbitrary properties into the global object prototype [1][3].
Impact
Successful prototype pollution can lead to severe consequences, including denial of service (e.g., triggering JavaScript exceptions) or, in many frameworks, remote code execution by hijacking property lookups that control application logic [4]. Patches targeting __proto__ or prototype can silently alter the behavior of all objects, potentially compromising authentication, authorization, or data flow [2][4].
Mitigation
The fix was released in Immer version 8.0.1, which introduces validation that rejects patches using reserved attributes like __proto__, prototype, and constructor [1][3]. Users are strongly advised to upgrade to at least 8.0.1 [2]. For applications that cannot upgrade immediately, any code path that passes external patch data to applyPatches should be reviewed and restricted to trusted sources only.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
immernpm | >= 7.0.0, < 8.0.1 | 8.0.1 |
Affected products
32- immer/immerdescription
- ghsa-coords31 versionspkg:npm/immerpkg:rpm/suse/cobbler&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/grafana-formula&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/mgr-libmod&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/mgr-osad&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/mgr-osad&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/prometheus-exporters-formula&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/prometheus-formula&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/py26-compat-salt&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/rhnlib&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/rhnlib&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/smdba&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-backend&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/spacewalk-backend&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-client-tools&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/spacewalk-client-tools&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-config&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-java&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-proxy&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/spacewalk-proxy-installer&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/spacewalk-utils&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/spacewalk-web&distro=SUSE%20Manager%20Proxy%20Module%204.1pkg:rpm/suse/spacewalk-web&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/subscription-matcher&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/susemanager&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/susemanager-doc-indexes&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/susemanager-docs_en&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/susemanager-schema&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/susemanager-sls&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/xpp3&distro=SUSE%20Manager%20Server%20Module%204.1pkg:rpm/suse/xstream&distro=SUSE%20Manager%20Server%20Module%204.1
>= 7.0.0, < 8.0.1+ 30 more
- (no CPE)range: >= 7.0.0, < 8.0.1
- (no CPE)range: < 3.0.0+git20190806.32c4bae0-5.6.4
- (no CPE)range: < 0.4.0-3.6.2
- (no CPE)range: < 4.1.7-3.16.2
- (no CPE)range: < 4.1.5-2.9.4
- (no CPE)range: < 4.1.5-2.9.4
- (no CPE)range: < 0.9.0-3.19.2
- (no CPE)range: < 0.3.1-3.6.2
- (no CPE)range: < 2016.11.10-6.11.2
- (no CPE)range: < 4.1.3-4.3.2
- (no CPE)range: < 4.1.3-4.3.2
- (no CPE)range: < 1.7.8-0.3.6.2
- (no CPE)range: < 4.1.21-4.22.7
- (no CPE)range: < 4.1.21-4.22.7
- (no CPE)range: < 4.1.9-4.12.4
- (no CPE)range: < 4.1.9-4.12.4
- (no CPE)range: < 4.1.5-3.3.2
- (no CPE)range: < 4.1.30-3.31.7
- (no CPE)range: < 4.1.4-3.9.4
- (no CPE)range: < 4.1.6-3.3.2
- (no CPE)range: < 4.1.14-3.12.2
- (no CPE)range: < 4.1.23-3.18.6
- (no CPE)range: < 4.1.23-3.18.6
- (no CPE)range: < 0.26-3.6.2
- (no CPE)range: < 4.1.24-3.20.2
- (no CPE)range: < 4.1-11.28.4
- (no CPE)range: < 4.1-11.28.2
- (no CPE)range: < 4.1.19-3.24.4
- (no CPE)range: < 4.1.21-3.26.2
- (no CPE)range: < 1.1.4c-11.2.2
- (no CPE)range: < 1.4.15-3.5.2
Patches
1da2bd4fa0edcfix: Fixed security issue #738: prototype pollution possible when applying patches CVE-2020-28477
3 files changed · +123 −3
src/plugins/patches.ts+12 −2 modified@@ -26,7 +26,8 @@ import { ArchtypeArray, die, isDraft, - isDraftable + isDraftable, + ArchtypeObject } from "../internal" export function enablePatches() { @@ -211,7 +212,16 @@ export function enablePatches() { let base: any = draft for (let i = 0; i < path.length - 1; i++) { - base = get(base, path[i]) + const parentType = getArchtype(base) + const p = path[i] + // See #738, avoid prototype pollution + if ( + (parentType === ArchtypeObject || parentType === ArchtypeArray) && + (p === "__proto__" || p === "constructor") + ) + die(24) + if (typeof base === "function" && p === "prototype") die(24) + base = get(base, p) if (typeof base !== "object") die(15, path.join("/")) }
src/utils/errors.ts+2 −1 modified@@ -38,7 +38,8 @@ const errors = { }, 23(thing: string) { return `'original' expects a draft, got: ${thing}` - } + }, + 24: "Patching reserved attributes like __proto__, prototype and constructor is not allowed" } as const export function die(error: keyof typeof errors, ...args: any[]): never {
__tests__/patch.js+109 −0 modified@@ -12,6 +12,8 @@ enableAllPlugins() jest.setTimeout(1000) +const isProd = process.env.NODE_ENV === "production" + function runPatchTest(base, producer, patches, inversePathes) { let resultProxies, resultEs5 @@ -1147,3 +1149,110 @@ test("#676 patching Date objects", () => { ) expect(rebuilt.date).toEqual(new Date("2020-11-10T08:08:08.003Z")) }) + +test("do not allow __proto__ polution - 738", () => { + const obj = {} + + // @ts-ignore + expect(obj.polluted).toBe(undefined) + expect(() => { + applyPatches({}, [ + {op: "add", path: ["__proto__", "polluted"], value: "yes"} + ]) + }).toThrow( + isProd + ? "24" + : "Patching reserved attributes like __proto__, prototype and constructor is not allowed" + ) + // @ts-ignore + expect(obj.polluted).toBe(undefined) +}) + +test("do not allow __proto__ polution using arrays - 738", () => { + const obj = {} + const ar = [] + + // @ts-ignore + expect(obj.polluted).toBe(undefined) + // @ts-ignore + expect(ar.polluted).toBe(undefined) + expect(() => { + applyPatches( + [], + [{op: "add", path: ["__proto__", "polluted"], value: "yes"}] + ) + }).toThrow( + isProd + ? "24" + : "Patching reserved attributes like __proto__, prototype and constructor is not allowed" + ) + // @ts-ignore + expect(obj.polluted).toBe(undefined) + // @ts-ignore + expect(ar.polluted).toBe(undefined) +}) + +test("do not allow prototype polution - 738", () => { + const obj = {} + + // @ts-ignore + expect(obj.polluted).toBe(undefined) + expect(() => { + applyPatches(Object, [ + {op: "add", path: ["prototype", "polluted"], value: "yes"} + ]) + }).toThrow( + isProd + ? "24" + : "Patching reserved attributes like __proto__, prototype and constructor is not allowed" + ) + // @ts-ignore + expect(obj.polluted).toBe(undefined) +}) + +test("do not allow constructor polution - 738", () => { + const obj = {} + + // @ts-ignore + expect(obj.polluted).toBe(undefined) + const t = {} + applyPatches(t, [{op: "replace", path: ["constructor"], value: "yes"}]) + expect(typeof t.constructor).toBe("function") + // @ts-ignore + expect(Object.polluted).toBe(undefined) +}) + +test("do not allow constructor.prototype polution - 738", () => { + const obj = {} + + // @ts-ignore + expect(obj.polluted).toBe(undefined) + expect(() => { + applyPatches({}, [ + {op: "add", path: ["constructor", "prototype", "polluted"], value: "yes"} + ]) + }).toThrow( + isProd + ? "24" + : "Patching reserved attributes like __proto__, prototype and constructor is not allowed" + ) + // @ts-ignore + expect(Object.polluted).toBe(undefined) +}) + +test("maps can store __proto__, prototype and constructor props", () => { + const obj = {} + const map = new Map() + map.set("__proto__", {}) + map.set("constructor", {}) + map.set("prototype", {}) + const newMap = applyPatches(map, [ + {op: "add", path: ["__proto__", "polluted"], value: "yes"}, + {op: "add", path: ["constructor", "polluted"], value: "yes"}, + {op: "add", path: ["prototype", "polluted"], value: "yes"} + ]) + expect(newMap.get("__proto__").polluted).toBe("yes") + expect(newMap.get("constructor").polluted).toBe("yes") + expect(newMap.get("prototype").polluted).toBe("yes") + expect(obj.polluted).toBe(undefined) +})
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-9qmh-276g-x5pjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-28477ghsaADVISORY
- github.com/immerjs/immer/blob/master/src/plugins/patches.ts%23L213ghsax_refsource_MISCWEB
- github.com/immerjs/immer/commit/da2bd4fa0edc9335543089fe7d290d6a346c40c5ghsaWEB
- github.com/immerjs/immer/issues/738ghsaWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1061986ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-IMMER-1019369ghsax_refsource_MISCWEB
- www.npmjs.com/package/immerghsaWEB
News mentions
0No linked articles in our index yet.