diff --git a/src/jsonata.js b/src/jsonata.js index 19b09409..a22d83bd 100644 --- a/src/jsonata.js +++ b/src/jsonata.js @@ -1295,6 +1295,13 @@ var jsonata = (function() { } for(var ii = 0; ii < matches.length; ii++) { var match = matches[ii]; + if (match && (match.isPrototypeOf(result) || match instanceof Object.constructor)) { + throw { + code: "D1010", + stack: (new Error()).stack, + position: expr.position + }; + } // evaluate the update value for each match var update = yield * evaluate(expr.update, match, environment); // update must be an object @@ -1539,7 +1546,7 @@ var jsonata = (function() { if (typeof err.token == 'undefined' && typeof proc.token !== 'undefined') { err.token = proc.token; } - err.position = proc.position; + err.position = proc.position || err.position; } throw err; } @@ -1971,6 +1978,7 @@ var jsonata = (function() { "T1007": "Attempted to partially apply a non-function. Did you mean ${{{token}}}?", "T1008": "Attempted to partially apply a non-function", "D1009": "Multiple key definitions evaluate to same key: {{value}}", + "D1010": "Attempted to access the Javascript object prototype", // Javascript specific "T1010": "The matcher function argument passed to function {{token}} does not return the correct object structure", "T2001": "The left side of the {{token}} operator must evaluate to a number", "T2002": "The right side of the {{token}} operator must evaluate to a number", diff --git a/test/implementation-tests.js b/test/implementation-tests.js index 9c58a0dc..8ca217bb 100644 --- a/test/implementation-tests.js +++ b/test/implementation-tests.js @@ -806,6 +806,32 @@ describe("Tests that are specific to a Javascript runtime", () => { }); }); }); + describe("Expressions that attempt to pollute the object prototype", function() { + it("should throw an error with __proto__", async function() { + const expr = jsonata('{} ~> | __proto__ | {"is_admin": true} |'); + expect(function() { + expr.evaluate(); + }) + .to.throw() + .to.deep.contain({ position: 7, code: "D1010" }); + }); + it("should throw an error with __lookupGetter__", async function() { + const expr = jsonata('{} ~> | __lookupGetter__("__proto__")() | {"is_admin": true} |'); + expect(function() { + expr.evaluate(); + }) + .to.throw() + .to.deep.contain({ position: 7, code: "D1010" }); + }); + it("should throw an error with constructor", async function() { + const expr = jsonata('{} ~> | constructor | {"is_admin": true} |'); + expect(function() { + expr.evaluate(); + }) + .to.throw() + .to.deep.contain({ position: 7, code: "D1010" }); + }); + }); }); describe("Test that yield platform specific results", () => {