Skip to content

systemtwosecurity/node26-vm-proxy-hasown

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Node v26.3.0 regression: vm + Proxy sandbox → membership checks lie

Upstream issue: nodejs/node#63739

When the object passed to vm.createContext() is a Proxy, properties of the contextified global are readable, listed by getOwnPropertyNames, and have a full own-property descriptor — yet in, Object.prototype.hasOwnProperty, Object.hasOwn, and Reflect.has all return false for them.

  • Regressed in: v26.3.0
  • Last good: v26.2.0 (v22.x also fine)
  • Cause (bisected): nodejs/node#63549PropertyDefinerCallback now returns Intercepted::kYes (correct, fixes the #52634 double-define), so properties live only on the sandbox Proxy. But PropertyQueryCallback resolves has-type queries via HasRealNamedProperty, which cannot see through a JSProxy. Pre-26.3.0 the double-define masked this: the query found the duplicate on the real context global.
  • A plain-object sandbox (vm.createContext({})) is not affected.

Run the core repro (zero dependencies)

node repro.js   # exit 0 = consistent, exit 1 = regression

Observed output:

check v22.22.3 v26.2.0 v26.3.0
foo (read) 42 42 42
getOwnPropertyDescriptor descriptor descriptor descriptor
getOwnPropertyNames includes true true true
hasOwnProperty true true false
Object.hasOwn true true false
"foo" in globalThis true true false
Reflect.has true true false

Real-world impact: breaks Jest (jest-impact/)

jest-environment-node (all Jest 29.x/30.x) passes a Proxy (GlobalProxy) as the vm sandbox, so inside any Jest test on v26.3.0 every copied node global is affected — e.g. 'setTimeout' in globalThis is false. Worst symptom: @sinonjs/fake-timers trusts hasOwnProperty at install time, so jest.useRealTimers() deletes setTimeout instead of restoring it.

cd jest-impact
npm install
npx jest        # passes on <= 26.2.0, both tests fail on 26.3.0

Files

  • repro.js — minimal pure-Node repro, doubles as a bisect test (exit code: git bisect run node repro.js)
  • jest-impact/ — demonstrates the downstream Jest fake-timers breakage

About

Minimal repro: Node v26.3.0 regression — vm.createContext(Proxy) makes 'in'/hasOwnProperty deny existing globals; breaks Jest fake timers

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors