diff --git a/cli/tests/run_tests.rs b/cli/tests/run_tests.rs index db6e6f685c20f9..31946fa2b9bf4f 100644 --- a/cli/tests/run_tests.rs +++ b/cli/tests/run_tests.rs @@ -1447,6 +1447,11 @@ mod run { // output: "run/single_compile_with_reload.ts.out", // }); + itest!(proto_accessor { + args: "run run/proto_accessor.js", + output: "run/proto_accessor.js.out", + }); + itest!(proto_exploit { args: "run run/proto_exploit.js", output: "run/proto_exploit.js.out", diff --git a/cli/tests/testdata/run/proto_accessor.js b/cli/tests/testdata/run/proto_accessor.js new file mode 100644 index 00000000000000..d8d6386861fb7c --- /dev/null +++ b/cli/tests/testdata/run/proto_accessor.js @@ -0,0 +1,5 @@ +class Test {} +const test = new Test(); +Object.setPrototypeOf(test, { test: "test" }); +console.log("Object.getPrototypeOf: ", Object.getPrototypeOf(test)); +console.log("__proto__: ", test.__proto__); diff --git a/cli/tests/testdata/run/proto_accessor.js.out b/cli/tests/testdata/run/proto_accessor.js.out new file mode 100644 index 00000000000000..0795403daae07e --- /dev/null +++ b/cli/tests/testdata/run/proto_accessor.js.out @@ -0,0 +1,2 @@ +Object.getPrototypeOf: { test: "test" } +__proto__: { test: "test" } diff --git a/cli/tests/testdata/run/proto_exploit.js.out b/cli/tests/testdata/run/proto_exploit.js.out index fde881dc558cb0..3bc6d74c544628 100644 --- a/cli/tests/testdata/run/proto_exploit.js.out +++ b/cli/tests/testdata/run/proto_exploit.js.out @@ -1,2 +1,4 @@ Before: [object Object] +Error: Prototype access via __proto__ attempted; __proto__ is not implemented in Deno due to security reasons. Use Object.setPrototypeOf instead. +[WILDCARD] After: [object Object] diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index adfc0d3602a265..7b1325f32a1f8b 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -1,10 +1,6 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. "use strict"; -// Removes the `__proto__` for security reasons. -// https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ -delete Object.prototype.__proto__; - // Remove Intl.v8BreakIterator because it is a non-standard API. delete Intl.v8BreakIterator; @@ -25,6 +21,8 @@ delete Intl.v8BreakIterator; ObjectDefineProperty, ObjectDefineProperties, ObjectFreeze, + ObjectGetPrototypeOf, + ObjectPrototype, ObjectPrototypeIsPrototypeOf, ObjectSetPrototypeOf, PromiseResolve, @@ -73,6 +71,23 @@ delete Intl.v8BreakIterator; setLanguage, } = window.__bootstrap.globalScope; + // Disables setting `__proto__` and emits a warning instead, for security reasons. + // https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ + ObjectDefineProperty(ObjectPrototype, "__proto__", { + configurable: true, + enumerable: false, + get() { + return ObjectGetPrototypeOf(this); + }, + set(_) { + console.warn( + new Error( + "Prototype access via __proto__ attempted; __proto__ is not implemented in Deno due to security reasons. Use Object.setPrototypeOf instead.", + ), + ); + }, + }); + let windowIsClosing = false; function windowClose() {