🐛 Bug Report
immer@11.1.9 regresses the identity of draft.constructor after the CVE fix for constructor.prototype / __proto__ access. The security fix is understandable, but the implementation now returns a fresh wrapper on each access, which changes equality behavior for equal drafts inside a producer.
To Reproduce
Steps to reproduce the behavior:
- Install
immer@11.1.9.
- Run the following test:
import assert from 'node:assert/strict';
import test from 'node:test';
import { produce } from 'immer';
import deepEqual from 'fast-deep-equal';
test('equal Immer drafts stay deep-equal', () => {
produce({ a: { x: 1 }, b: { x: 1 } }, (draft) => {
assert.equal(deepEqual(draft.a, draft.b), true);
assert.equal(draft.a.constructor === draft.b.constructor, true);
});
});
- Compare the result with
immer@11.1.8.
Observed behavior
With immer@11.1.9, equal drafts no longer expose a stable constructor identity:
deepEqual(draft.a, draft.b) can fail where it previously passed
draft.a.constructor === draft.b.constructor is false
This is caused by the constructor proxy wrapper added in the CVE fix.
Expected behavior
Equal drafts should preserve stable observable behavior for normal property reads, including constructor, while still blocking prototype pollution via constructor.prototype and __proto__.
Environment
We only accept bug reports against the latest Immer version.
Notes
I validated that:
11.1.8 passes the repro
11.1.9 fails the repro
- a narrow fix that caches the constructor wrapper per underlying constructor restores the behavior while keeping the pollution guard in place
🐛 Bug Report
immer@11.1.9regresses the identity ofdraft.constructorafter the CVE fix forconstructor.prototype/__proto__access. The security fix is understandable, but the implementation now returns a fresh wrapper on each access, which changes equality behavior for equal drafts inside a producer.To Reproduce
Steps to reproduce the behavior:
immer@11.1.9.immer@11.1.8.Observed behavior
With
immer@11.1.9, equal drafts no longer expose a stableconstructoridentity:deepEqual(draft.a, draft.b)can fail where it previously passeddraft.a.constructor === draft.b.constructorisfalseThis is caused by the
constructorproxy wrapper added in the CVE fix.Expected behavior
Equal drafts should preserve stable observable behavior for normal property reads, including
constructor, while still blocking prototype pollution viaconstructor.prototypeand__proto__.Environment
We only accept bug reports against the latest Immer version.
11.1.9(also happens with11.1.11)setUseProxies(true)setUseProxies(false)(ES5 only)Notes
I validated that:
11.1.8passes the repro11.1.9fails the repro