diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index df871c0b0cb..452f25ba1a5 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -214,6 +214,17 @@ class PropNameTracking extends DataFlow::Configuration { ) } + override predicate isBarrier(DataFlow::Node node) { + super.isBarrier(node) + or + exists(ConditionGuardNode guard, SsaRefinementNode refinement | + node = DataFlow::ssaDefinitionNode(refinement) and + refinement.getGuard() = guard and + guard.getTest() instanceof VarAccess and + guard.getOutcome() = false + ) + } + override predicate isBarrierGuard(DataFlow::BarrierGuardNode node) { node instanceof EqualityGuard or node instanceof HasOwnPropertyGuard or @@ -307,6 +318,18 @@ class TypeofGuard extends DataFlow::LabeledBarrierGuardNode, DataFlow::ValueNode typeofStr = "function" and label = "__proto__" ) + or + e = typeof.getOperand() and + outcome = astNode.getPolarity().booleanNot() and + ( + // If something is not an object, sanitize object, as both must end + // in non-function prototype object. + typeofStr = "object" and + label instanceof UnsafePropLabel + or + typeofStr = "function" and + label = "constructor" + ) } } diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected index 90a245ac8ba..b869a4c9158 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected @@ -314,24 +314,12 @@ nodes | PrototypePollutionUtility/tests.js:128:20:128:27 | src[key] | | PrototypePollutionUtility/tests.js:128:24:128:26 | key | | PrototypePollutionUtility/tests.js:128:24:128:26 | key | -| PrototypePollutionUtility/tests.js:140:16:140:18 | src | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:144:16:144:18 | key | -| PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:31 | src | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:33:144:35 | key | -| PrototypePollutionUtility/tests.js:144:33:144:35 | key | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | @@ -628,6 +616,28 @@ nodes | PrototypePollutionUtility/tests.js:240:36:240:44 | data[key] | | PrototypePollutionUtility/tests.js:240:41:240:43 | key | | PrototypePollutionUtility/tests.js:240:41:240:43 | key | +| PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | +| PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:53 | src | +| PrototypePollutionUtility/tests.js:257:51:257:53 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:55:257:57 | key | +| PrototypePollutionUtility/tests.js:257:55:257:57 | key | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | | examples/PrototypePollutionUtility.js:1:21:1:23 | src | @@ -1113,7 +1123,6 @@ edges | PrototypePollutionUtility/tests.js:128:24:128:26 | key | PrototypePollutionUtility/tests.js:128:20:128:27 | src[key] | | PrototypePollutionUtility/tests.js:128:24:128:26 | key | PrototypePollutionUtility/tests.js:128:20:128:27 | src[key] | | PrototypePollutionUtility/tests.js:128:24:128:26 | key | PrototypePollutionUtility/tests.js:128:20:128:27 | src[key] | -| PrototypePollutionUtility/tests.js:140:16:140:18 | src | PrototypePollutionUtility/tests.js:144:29:144:31 | src | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | @@ -1121,25 +1130,6 @@ edges | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | | PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:16:144:18 | key | -| PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:33:144:35 | key | -| PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:33:144:35 | key | -| PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:33:144:35 | key | -| PrototypePollutionUtility/tests.js:143:14:143:16 | key | PrototypePollutionUtility/tests.js:144:33:144:35 | key | -| PrototypePollutionUtility/tests.js:144:29:144:31 | src | PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:140:16:140:18 | src | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:140:16:140:18 | src | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:140:16:140:18 | src | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | PrototypePollutionUtility/tests.js:144:23:144:37 | clone(src[key]) | -| PrototypePollutionUtility/tests.js:144:33:144:35 | key | PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | -| PrototypePollutionUtility/tests.js:144:33:144:35 | key | PrototypePollutionUtility/tests.js:144:29:144:36 | src[key] | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | PrototypePollutionUtility/tests.js:152:22:152:24 | dst | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | PrototypePollutionUtility/tests.js:152:22:152:24 | dst | | PrototypePollutionUtility/tests.js:149:31:149:33 | dst | PrototypePollutionUtility/tests.js:152:22:152:24 | dst | @@ -1515,6 +1505,40 @@ edges | PrototypePollutionUtility/tests.js:240:36:240:44 | data[key] | PrototypePollutionUtility/tests.js:229:38:229:42 | value | | PrototypePollutionUtility/tests.js:240:41:240:43 | key | PrototypePollutionUtility/tests.js:240:36:240:44 | data[key] | | PrototypePollutionUtility/tests.js:240:41:240:43 | key | PrototypePollutionUtility/tests.js:240:36:240:44 | data[key] | +| PrototypePollutionUtility/tests.js:252:29:252:31 | src | PrototypePollutionUtility/tests.js:257:51:257:53 | src | +| PrototypePollutionUtility/tests.js:252:29:252:31 | src | PrototypePollutionUtility/tests.js:257:51:257:53 | src | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:20:257:22 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:55:257:57 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:55:257:57 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:55:257:57 | key | +| PrototypePollutionUtility/tests.js:255:14:255:16 | key | PrototypePollutionUtility/tests.js:257:55:257:57 | key | +| PrototypePollutionUtility/tests.js:257:51:257:53 | src | PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:53 | src | PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:252:29:252:31 | src | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | PrototypePollutionUtility/tests.js:257:27:257:59 | mergeWi ... c[key]) | +| PrototypePollutionUtility/tests.js:257:55:257:57 | key | PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | +| PrototypePollutionUtility/tests.js:257:55:257:57 | key | PrototypePollutionUtility/tests.js:257:51:257:58 | src[key] | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:5:19:5:21 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:5:19:5:21 | dst | | examples/PrototypePollutionUtility.js:1:16:1:18 | dst | examples/PrototypePollutionUtility.js:7:13:7:15 | dst | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js index 33ff9e6f855..96a2f1bf135 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/tests.js @@ -240,3 +240,22 @@ function deepSetCallerBad(data) { deepSetBad(map1, 'x', key, data[key]); } } + +function maybeCopy(x) { + if (x && typeof x === 'object') { + return {...x}; + } else { + return x; + } +} + +function mergeWithCopy(dst, src) { + if (dst == null) return src; + let result = maybeCopy(dst); + for (let key in src) { + if (src.hasOwnProperty(key)) { + result[key] = mergeWithCopy(dst[key], src[key]); // OK + } + } + return result; +}