diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 8f9dddf53ca..852184b1821 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 e57cc8dc854..6bb2b8c93aa 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), +);