| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ac9599a commit 812140c
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -705,3 +705,27 @@ class SomeClass { | |||
| 705 | 705 | ObjectDefineProperty(SomeClass.prototype, 'readOnlyProperty', kEnumerableProperty); | |
| 706 | 706 | console.log(new SomeClass().readOnlyProperty); // genuine data | |
| 707 | 707 | ``` | |
| 708 | + | ||
| 709 | + ### Defining a `Proxy` handler | ||
| 710 | + | ||
| 711 | + When defining a `Proxy`, the handler object could be at risk of prototype | ||
| 712 | + pollution when using a plain object literal: | ||
| 713 | + | ||
| 714 | + ```js | ||
| 715 | + // User-land | ||
| 716 | + Object.prototype.get = () => 'Unrelated user-provided data'; | ||
| 717 | + | ||
| 718 | + // Core | ||
| 719 | + const objectToProxy = { someProperty: 'genuine value' }; | ||
| 720 | + | ||
| 721 | + const proxyWithPlainObjectLiteral = new Proxy(objectToProxy, { | ||
| 722 | + has() { return false; }, | ||
| 723 | + }); | ||
| 724 | + console.log(proxyWithPlainObjectLiteral.someProperty); // Unrelated user-provided data | ||
| 725 | + | ||
| 726 | + const proxyWithNullPrototypeObject = new Proxy(objectToProxy, { | ||
| 727 | + __proto__: null, | ||
| 728 | + has() { return false; }, | ||
| 729 | + }); | ||
| 730 | + console.log(proxyWithNullPrototypeObject.someProperty); // genuine value | ||
| 731 | + ``` | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -117,6 +117,7 @@ function createAgentProxy(domain, client) { | |||
| 117 | 117 | }; | |
| 118 | 118 | ||
| 119 | 119 | return new Proxy(agent, { | |
| 120 | + __proto__: null, | ||
| 120 | 121 | get(target, name) { | |
| 121 | 122 | if (name in target) return target[name]; | |
| 122 | 123 | return function callVirtualMethod(params) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -987,6 +987,7 @@ function trackAssignmentsTypedArray(typedArray) { | |||
| 987 | 987 | } | |
| 988 | 988 | ||
| 989 | 989 | return new Proxy(typedArray, { | |
| 990 | + __proto__: null, | ||
| 990 | 991 | get(obj, prop, receiver) { | |
| 991 | 992 | if (prop === 'copyAssigned') { | |
| 992 | 993 | return copyAssigned; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -210,6 +210,8 @@ const wrapper = [ | |||
| 210 | 210 | ]; | |
| 211 | 211 | ||
| 212 | 212 | let wrapperProxy = new Proxy(wrapper, { | |
| 213 | + __proto__: null, | ||
| 214 | + | ||
| 213 | 215 | set(target, property, value, receiver) { | |
| 214 | 216 | patched = true; | |
| 215 | 217 | return ReflectSet(target, property, value, receiver); | |
@@ -718,6 +720,8 @@ function emitCircularRequireWarning(prop) { | |||
| 718 | 720 | // A Proxy that can be used as the prototype of a module.exports object and | |
| 719 | 721 | // warns when non-existent properties are accessed. | |
| 720 | 722 | const CircularRequirePrototypeWarningProxy = new Proxy({}, { | |
| 723 | + __proto__: null, | ||
| 724 | + | ||
| 721 | 725 | get(target, prop) { | |
| 722 | 726 | // Allow __esModule access in any case because it is used in the output | |
| 723 | 727 | // of transpiled code to determine whether something comes from an | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,6 +45,10 @@ new RuleTester({ | |||
| 45 | 45 | 'ReflectDefineProperty({}, "key", { "__proto__": null })', | |
| 46 | 46 | 'ObjectDefineProperty({}, "key", { \'__proto__\': null })', | |
| 47 | 47 | 'ReflectDefineProperty({}, "key", { \'__proto__\': null })', | |
| 48 | + 'new Proxy({}, otherObject)', | ||
| 49 | + 'new Proxy({}, someFactory())', | ||
| 50 | + 'new Proxy({}, { __proto__: null })', | ||
| 51 | + 'new Proxy({}, { __proto__: null, ...{} })', | ||
| 48 | 52 | ], | |
| 49 | 53 | invalid: [ | |
| 50 | 54 | { | |
@@ -183,5 +187,21 @@ new RuleTester({ | |||
| 183 | 187 | code: 'StringPrototypeSplit("some string", /some regex/)', | |
| 184 | 188 | errors: [{ message: /looks up the Symbol\.split property/ }], | |
| 185 | 189 | }, | |
| 190 | + { | ||
| 191 | + code: 'new Proxy({}, {})', | ||
| 192 | + errors: [{ message: /null-prototype/ }] | ||
| 193 | + }, | ||
| 194 | + { | ||
| 195 | + code: 'new Proxy({}, { [`__proto__`]: null })', | ||
| 196 | + errors: [{ message: /null-prototype/ }] | ||
| 197 | + }, | ||
| 198 | + { | ||
| 199 | + code: 'new Proxy({}, { __proto__: Object.prototype })', | ||
| 200 | + errors: [{ message: /null-prototype/ }] | ||
| 201 | + }, | ||
| 202 | + { | ||
| 203 | + code: 'new Proxy({}, { ...{ __proto__: null } })', | ||
| 204 | + errors: [{ message: /null-prototype/ }] | ||
| 205 | + }, | ||
| 186 | 206 | ] | |
| 187 | 207 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -128,6 +128,23 @@ module.exports = { | |||
| 128 | 128 | ...createUnsafeStringMethodReport(context, 'StringPrototypeReplaceAll', 'Symbol.replace'), | |
| 129 | 129 | ...createUnsafeStringMethodReport(context, 'StringPrototypeSearch', 'Symbol.search'), | |
| 130 | 130 | ...createUnsafeStringMethodReport(context, 'StringPrototypeSplit', 'Symbol.split'), | |
| 131 | + | ||
| 132 | + 'NewExpression[callee.name="Proxy"][arguments.1.type="ObjectExpression"]'(node) { | ||
| 133 | + for (const { key, value } of node.arguments[1].properties) { | ||
| 134 | + if ( | ||
| 135 | + key != null && value != null && | ||
| 136 | + ((key.type === 'Identifier' && key.name === '__proto__') || | ||
| 137 | + (key.type === 'Literal' && key.value === '__proto__')) && | ||
| 138 | + value.type === 'Literal' && value.value === null | ||
| 139 | + ) { | ||
| 140 | + return; | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + context.report({ | ||
| 144 | + node, | ||
| 145 | + message: 'Proxy handler must be a null-prototype object' | ||
| 146 | + }); | ||
| 147 | + } | ||
| 131 | 148 | }; | |
| 132 | 149 | }, | |
| 133 | 150 | }; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments