diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll index 19153304811..e9ff8bb5055 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll @@ -2018,6 +2018,7 @@ private class BarrierGuardFunction extends Function { BarrierGuardNode guard; boolean guardOutcome; string label; + int paramIndex; BarrierGuardFunction() { barrierGuardIsRelevant(guard) and @@ -2041,8 +2042,7 @@ private class BarrierGuardFunction extends Function { sanitizedParameter.flowsToExpr(e) and barrierGuardBlocksExpr(guard, guardOutcome, e, label) ) and - getNumParameter() = 1 and - sanitizedParameter.getParameter() = getParameter(0) + sanitizedParameter.getParameter() = getParameter(paramIndex) } /** @@ -2050,10 +2050,10 @@ private class BarrierGuardFunction extends Function { */ predicate isBarrierCall(DataFlow::CallNode call, Expr e, boolean outcome, string lbl) { exists(DataFlow::Node arg | + argumentPassing(pragma[only_bind_into](call), pragma[only_bind_into](arg), + pragma[only_bind_into](this), pragma[only_bind_into](sanitizedParameter)) and arg.asExpr() = e and - arg = call.getArgument(0) and - call.getNumArgument() = 1 and - argumentPassing(call, arg, this, sanitizedParameter) and + arg = call.getArgument(paramIndex) and outcome = guardOutcome and lbl = label ) diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected index f16f3e4ef55..28a0fc8bd83 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected @@ -1528,6 +1528,31 @@ nodes | tests.js:571:24:571:31 | src[key] | | tests.js:571:28:571:30 | key | | tests.js:571:28:571:30 | key | +| tests.js:576:30:576:32 | src | +| tests.js:576:30:576:32 | src | +| tests.js:577:14:577:16 | key | +| tests.js:577:14:577:16 | key | +| tests.js:577:14:577:16 | key | +| tests.js:580:38:580:40 | src | +| tests.js:580:38:580:40 | src | +| tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:45 | src[key] | +| tests.js:582:17:582:19 | key | +| tests.js:582:17:582:19 | key | +| tests.js:582:17:582:19 | key | +| tests.js:582:24:582:26 | src | +| tests.js:582:24:582:26 | src | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | +| tests.js:582:28:582:30 | key | +| tests.js:582:28:582:30 | key | edges | examples/PrototypePollutingFunction.js:1:16:1:18 | dst | examples/PrototypePollutingFunction.js:5:19:5:21 | dst | | examples/PrototypePollutingFunction.js:1:16:1:18 | dst | examples/PrototypePollutingFunction.js:5:19:5:21 | dst | @@ -3461,6 +3486,38 @@ edges | tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | | tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | | tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | +| tests.js:576:30:576:32 | src | tests.js:580:38:580:40 | src | +| tests.js:576:30:576:32 | src | tests.js:580:38:580:40 | src | +| tests.js:576:30:576:32 | src | tests.js:582:24:582:26 | src | +| tests.js:576:30:576:32 | src | tests.js:582:24:582:26 | src | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:17:582:19 | key | +| tests.js:577:14:577:16 | key | tests.js:582:28:582:30 | key | +| tests.js:577:14:577:16 | key | tests.js:582:28:582:30 | key | +| tests.js:577:14:577:16 | key | tests.js:582:28:582:30 | key | +| tests.js:577:14:577:16 | key | tests.js:582:28:582:30 | key | +| tests.js:580:38:580:40 | src | tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:40 | src | tests.js:580:38:580:45 | src[key] | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:580:38:580:45 | src[key] | tests.js:576:30:576:32 | src | +| tests.js:582:24:582:26 | src | tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:26 | src | tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:26 | src | tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:26 | src | tests.js:582:24:582:31 | src[key] | +| tests.js:582:24:582:31 | src[key] | tests.js:582:24:582:31 | src[key] | +| tests.js:582:28:582:30 | key | tests.js:582:24:582:31 | src[key] | +| tests.js:582:28:582:30 | key | tests.js:582:24:582:31 | src[key] | +| tests.js:582:28:582:30 | key | tests.js:582:24:582:31 | src[key] | +| tests.js:582:28:582:30 | key | tests.js:582:24:582:31 | src[key] | #select | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | examples/PrototypePollutingFunction.js:2:14:2:16 | key | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | examples/PrototypePollutingFunction.js:2:21:2:23 | src | src | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | dst | | path-assignment.js:15:13:15:18 | target | path-assignment.js:8:19:8:25 | keys[i] | path-assignment.js:15:13:15:18 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | path-assignment.js:8:19:8:25 | keys[i] | here | path-assignment.js:15:13:15:18 | target | target | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js index a1fc92a5776..2efba5e773e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js @@ -572,3 +572,18 @@ function copyHasOwnProperty3(dst, src) { } } } + +function indirectHasOwn(dst, src) { + for (let key in src) { + if (!src.hasOwnProperty(key)) continue; + if (hasOwn(dst, key) && isObject(dst[key])) { + indirectHasOwn(dst[key], src[key]); + } else { + dst[key] = src[key]; + } + } +} + +function hasOwn(obj, key) { + return obj.hasOwnProperty(key) +}