From 952b755091d60067ad957480dbe9dc5d921355fa Mon Sep 17 00:00:00 2001 From: subotac <73706465+subotac@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:29:38 +0300 Subject: [PATCH] vm: preserve global function declaration restrictions Keep the global proxy's DontDelete attribute when the sandbox also contains the property, so lexical redeclarations are rejected. Signed-off-by: subotac <73706465+subotac@users.noreply.github.com> --- src/node_contextify.cc | 13 +++++++++++++ test/parallel/test-vm-global-restricted-property.js | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 8f9dddf53cae..852184b18215 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -534,6 +534,19 @@ Intercepted ContextifyContext::PropertyQueryCallback( if (!maybe_attr.FromMaybe(false)) { return Intercepted::kNo; } + + // Function declarations can be reflected as configurable sandbox + // properties while V8 tracks their non-configurable global bindings. + PropertyAttribute global_attr; + if (ctx->global_proxy() + ->GetRealNamedPropertyAttributes(context, property) + .To(&global_attr)) { + attr = static_cast( + static_cast(attr) | + (static_cast(global_attr) & + static_cast(PropertyAttribute::DontDelete))); + } + args.GetReturnValue().Set(attr); return Intercepted::kYes; } else { diff --git a/test/parallel/test-vm-global-restricted-property.js b/test/parallel/test-vm-global-restricted-property.js index e57cc8dc8546..6bb2b8c93aae 100644 --- a/test/parallel/test-vm-global-restricted-property.js +++ b/test/parallel/test-vm-global-restricted-property.js @@ -18,3 +18,11 @@ assert.throws( () => vm.runInContext('let foo = 2;', ctx), vm.runInContext('SyntaxError', ctx), ); + +// Global function declarations create non-configurable bindings even +// though the corresponding sandbox properties are configurable. +vm.runInContext('function bar() {}', ctx); +assert.throws( + () => vm.runInContext('let bar;', ctx), + vm.runInContext('SyntaxError', ctx), +);