diff --git a/javascript/ql/lib/semmle/javascript/Arrays.qll b/javascript/ql/lib/semmle/javascript/Arrays.qll index 37a3e5351a4..64ed34ae631 100644 --- a/javascript/ql/lib/semmle/javascript/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/Arrays.qll @@ -344,6 +344,14 @@ private module ArrayLibraries { result = DataFlow::globalVarRef("Array").getAMemberCall("from") or result = DataFlow::moduleImport("array-from").getACall() + or + // Array.prototype.slice.call acts the same as Array.from, and is sometimes used with e.g. the arguments object. + result = + DataFlow::globalVarRef("Array") + .getAPropertyRead("prototype") + .getAPropertyRead("slice") + .getAMethodCall("call") and + result.getNumArgument() = 1 } /** diff --git a/javascript/ql/lib/semmle/javascript/PackageExports.qll b/javascript/ql/lib/semmle/javascript/PackageExports.qll index 17b91448620..01cd134ff0c 100644 --- a/javascript/ql/lib/semmle/javascript/PackageExports.qll +++ b/javascript/ql/lib/semmle/javascript/PackageExports.qll @@ -18,34 +18,10 @@ DataFlow::Node getALibraryInputParameter() { | result = func.getParameter(any(int arg | arg >= bound)) or - result = getAnArgumentsRead(func.getFunction()) - or result = func.getFunction().getArgumentsVariable().getAnAccess().flow() ) } -private DataFlow::SourceNode getAnArgumentsRead(Function func) { - exists(DataFlow::PropRead read | - not read.getPropertyName() = "length" and - result = read - | - read.getBase() = func.getArgumentsVariable().getAnAccess().flow() - or - exists(DataFlow::MethodCallNode call | - call = - DataFlow::globalVarRef("Array") - .getAPropertyRead("prototype") - .getAPropertyRead("slice") - .getAMethodCall("call") - or - call = DataFlow::globalVarRef("Array").getAMethodCall("from") - | - call.getArgument(0) = func.getArgumentsVariable().getAnAccess().flow() and - call.flowsTo(read.getBase()) - ) - ) -} - private import NodeModuleResolutionImpl as NodeModule /** diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index 2b0ab442fff..8d7658bc603 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -1661,9 +1661,7 @@ module DataFlow { ) } - /** - * A step from a reflective parameter node to each parameter. - */ + /** A load step from a reflective parameter node to each parameter. */ private class ReflectiveParamsStep extends PreCallGraphStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i | @@ -1675,6 +1673,17 @@ module DataFlow { } } + /** A taint step from the reflective parameters node to any parameter. */ + private class ReflectiveParamsTaintStep extends TaintTracking::SharedTaintStep { + override predicate step(DataFlow::Node obj, DataFlow::Node element) { + exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f | + f.getFunction() = params.getFunction() and + obj = params and + element = f.getAParameter() + ) + } + } + /** * Holds if there is a step from `pred` to `succ` through a field accessed through `this` in a class. */ diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 1b2aa7949f0..b0dfcbdc60b 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -6,6 +6,7 @@ typeInferenceMismatch | call-apply.js:25:14:25:21 | source() | call-apply.js:21:1:23:1 | the arguments object of function foo1_sink | | call-apply.js:25:14:25:21 | source() | call-apply.js:27:6:27:32 | reflective call | | call-apply.js:25:14:25:21 | source() | call-apply.js:30:6:30:35 | reflective call | +| call-apply.js:25:14:25:21 | source() | call-apply.js:31:6:31:35 | reflective call | | call-apply.js:25:14:25:21 | source() | call-apply.js:62:3:64:3 | the arguments object of function sinkArguments1 | | call-apply.js:25:14:25:21 | source() | call-apply.js:65:3:67:3 | the arguments object of function sinkArguments0 | | call-apply.js:25:14:25:21 | source() | call-apply.js:69:3:72:3 | the arguments object of function fowardArguments | @@ -54,6 +55,8 @@ typeInferenceMismatch | call-apply.js:25:14:25:21 | source() | call-apply.js:22:8:22:11 | arg1 | | call-apply.js:25:14:25:21 | source() | call-apply.js:27:6:27:32 | foo1.ca ... ce, "") | | call-apply.js:25:14:25:21 | source() | call-apply.js:30:6:30:35 | foo1.ap ... e, ""]) | +| call-apply.js:25:14:25:21 | source() | call-apply.js:31:6:31:35 | foo2.ap ... e, ""]) | +| call-apply.js:25:14:25:21 | source() | call-apply.js:38:6:38:29 | foo1_ap ... e, ""]) | | call-apply.js:25:14:25:21 | source() | call-apply.js:44:6:44:28 | foo1_ca ... e, ""]) | | call-apply.js:25:14:25:21 | source() | call-apply.js:45:6:45:28 | foo1_ca ... ource]) | | call-apply.js:25:14:25:21 | source() | call-apply.js:63:10:63:21 | arguments[1] | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected index fdab06e099c..f457e591d6b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected @@ -22,6 +22,12 @@ nodes | lib/lib.js:27:10:27:19 | id("safe") | | lib/lib.js:28:13:28:13 | y | | lib/lib.js:28:13:28:13 | y | +| lib/lib.js:32:32:32:40 | arguments | +| lib/lib.js:32:32:32:40 | arguments | +| lib/lib.js:35:1:37:1 | the arguments object of function usedWithArguments | +| lib/lib.js:35:28:35:31 | name | +| lib/lib.js:36:13:36:16 | name | +| lib/lib.js:36:13:36:16 | name | | lib/moduleLib/moduleLib.js:1:28:1:31 | name | | lib/moduleLib/moduleLib.js:1:28:1:31 | name | | lib/moduleLib/moduleLib.js:2:13:2:16 | name | @@ -238,6 +244,11 @@ edges | lib/lib.js:27:6:27:19 | y | lib/lib.js:28:13:28:13 | y | | lib/lib.js:27:6:27:19 | y | lib/lib.js:28:13:28:13 | y | | lib/lib.js:27:10:27:19 | id("safe") | lib/lib.js:27:6:27:19 | y | +| lib/lib.js:32:32:32:40 | arguments | lib/lib.js:35:1:37:1 | the arguments object of function usedWithArguments | +| lib/lib.js:32:32:32:40 | arguments | lib/lib.js:35:1:37:1 | the arguments object of function usedWithArguments | +| lib/lib.js:35:1:37:1 | the arguments object of function usedWithArguments | lib/lib.js:35:28:35:31 | name | +| lib/lib.js:35:28:35:31 | name | lib/lib.js:36:13:36:16 | name | +| lib/lib.js:35:28:35:31 | name | lib/lib.js:36:13:36:16 | name | | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | @@ -428,6 +439,7 @@ edges | lib/indirect.js:2:5:2:17 | /k*h/.test(x) | lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x | This $@ that depends on $@ may run slow on strings with many repetitions of 'k'. | lib/indirect.js:2:6:2:7 | k* | regular expression | lib/indirect.js:1:32:1:32 | x | library input | | lib/lib.js:4:2:4:18 | regexp.test(name) | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/lib.js:1:15:1:16 | a* | regular expression | lib/lib.js:3:28:3:31 | name | library input | | lib/lib.js:8:2:8:17 | /f*g/.test(name) | lib/lib.js:7:19:7:22 | name | lib/lib.js:8:13:8:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/lib.js:8:3:8:4 | f* | regular expression | lib/lib.js:7:19:7:22 | name | library input | +| lib/lib.js:36:2:36:17 | /f*g/.test(name) | lib/lib.js:32:32:32:40 | arguments | lib/lib.js:36:13:36:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/lib.js:36:3:36:4 | f* | regular expression | lib/lib.js:32:32:32:40 | arguments | library input | | lib/moduleLib/moduleLib.js:2:2:2:17 | /a*b/.test(name) | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/moduleLib/moduleLib.js:2:3:2:4 | a* | regular expression | lib/moduleLib/moduleLib.js:1:28:1:31 | name | library input | | lib/otherLib/js/src/index.js:2:2:2:17 | /a*b/.test(name) | lib/otherLib/js/src/index.js:1:28:1:31 | name | lib/otherLib/js/src/index.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/otherLib/js/src/index.js:2:3:2:4 | a* | regular expression | lib/otherLib/js/src/index.js:1:28:1:31 | name | library input | | lib/snapdragon.js:7:15:7:32 | this.match(/aa*$/) | lib/snapdragon.js:3:34:3:38 | input | lib/snapdragon.js:7:15:7:18 | this | This $@ that depends on $@ may run slow on strings starting with 'a' and with many repetitions of 'a'. | lib/snapdragon.js:7:28:7:29 | a* | regular expression | lib/snapdragon.js:3:34:3:38 | input | library input | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/lib/lib.js index f7307325978..5c892f328a3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/lib/lib.js @@ -33,7 +33,7 @@ module.exports.useArguments = function () { } function usedWithArguments(name) { - /f*g/.test(name); // NOT OK - bit not yet recognized [INCONSITENCY] + /f*g/.test(name); // NOT OK } module.exports.snapdragon = require("./snapdragon") \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected index 3ae07da58ea..662b3315c80 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected @@ -29,7 +29,6 @@ nodes | lib.js:20:14:20:22 | arguments | | lib.js:20:14:20:22 | arguments | | lib.js:20:14:20:25 | arguments[1] | -| lib.js:20:14:20:25 | arguments[1] | | lib.js:22:3:22:14 | obj[path[0]] | | lib.js:22:3:22:14 | obj[path[0]] | | lib.js:22:7:22:10 | path | @@ -40,8 +39,12 @@ nodes | lib.js:26:10:26:21 | obj[path[0]] | | lib.js:26:14:26:17 | path | | lib.js:26:14:26:20 | path[0] | +| lib.js:30:9:30:52 | args | +| lib.js:30:16:30:52 | Array.p ... uments) | +| lib.js:30:43:30:51 | arguments | +| lib.js:30:43:30:51 | arguments | | lib.js:32:7:32:20 | path | -| lib.js:32:14:32:20 | args[1] | +| lib.js:32:14:32:17 | args | | lib.js:32:14:32:20 | args[1] | | lib.js:34:3:34:14 | obj[path[0]] | | lib.js:34:3:34:14 | obj[path[0]] | @@ -54,7 +57,6 @@ nodes | lib.js:40:7:40:20 | path | | lib.js:40:14:40:17 | args | | lib.js:40:14:40:20 | args[1] | -| lib.js:40:14:40:20 | args[1] | | lib.js:42:3:42:14 | obj[path[0]] | | lib.js:42:3:42:14 | obj[path[0]] | | lib.js:42:7:42:10 | path | @@ -81,7 +83,6 @@ nodes | lib.js:83:14:83:22 | arguments | | lib.js:83:14:83:22 | arguments | | lib.js:83:14:83:25 | arguments[1] | -| lib.js:83:14:83:25 | arguments[1] | | lib.js:86:7:86:26 | proto | | lib.js:86:15:86:26 | obj[path[0]] | | lib.js:86:19:86:22 | path | @@ -101,7 +102,6 @@ nodes | lib.js:104:13:104:21 | arguments | | lib.js:104:13:104:21 | arguments | | lib.js:104:13:104:24 | arguments[1] | -| lib.js:104:13:104:24 | arguments[1] | | lib.js:108:3:108:10 | obj[one] | | lib.js:108:3:108:10 | obj[one] | | lib.js:108:7:108:9 | one | @@ -197,7 +197,6 @@ edges | lib.js:20:14:20:22 | arguments | lib.js:20:14:20:25 | arguments[1] | | lib.js:20:14:20:22 | arguments | lib.js:20:14:20:25 | arguments[1] | | lib.js:20:14:20:25 | arguments[1] | lib.js:20:7:20:25 | path | -| lib.js:20:14:20:25 | arguments[1] | lib.js:20:7:20:25 | path | | lib.js:22:7:22:10 | path | lib.js:22:7:22:13 | path[0] | | lib.js:22:7:22:13 | path[0] | lib.js:22:3:22:14 | obj[path[0]] | | lib.js:22:7:22:13 | path[0] | lib.js:22:3:22:14 | obj[path[0]] | @@ -206,8 +205,12 @@ edges | lib.js:26:14:26:17 | path | lib.js:26:14:26:20 | path[0] | | lib.js:26:14:26:20 | path[0] | lib.js:26:10:26:21 | obj[path[0]] | | lib.js:26:14:26:20 | path[0] | lib.js:26:10:26:21 | obj[path[0]] | +| lib.js:30:9:30:52 | args | lib.js:32:14:32:17 | args | +| lib.js:30:16:30:52 | Array.p ... uments) | lib.js:30:9:30:52 | args | +| lib.js:30:43:30:51 | arguments | lib.js:30:16:30:52 | Array.p ... uments) | +| lib.js:30:43:30:51 | arguments | lib.js:30:16:30:52 | Array.p ... uments) | | lib.js:32:7:32:20 | path | lib.js:34:7:34:10 | path | -| lib.js:32:14:32:20 | args[1] | lib.js:32:7:32:20 | path | +| lib.js:32:14:32:17 | args | lib.js:32:14:32:20 | args[1] | | lib.js:32:14:32:20 | args[1] | lib.js:32:7:32:20 | path | | lib.js:34:7:34:10 | path | lib.js:34:7:34:13 | path[0] | | lib.js:34:7:34:13 | path[0] | lib.js:34:3:34:14 | obj[path[0]] | @@ -219,7 +222,6 @@ edges | lib.js:40:7:40:20 | path | lib.js:42:7:42:10 | path | | lib.js:40:14:40:17 | args | lib.js:40:14:40:20 | args[1] | | lib.js:40:14:40:20 | args[1] | lib.js:40:7:40:20 | path | -| lib.js:40:14:40:20 | args[1] | lib.js:40:7:40:20 | path | | lib.js:42:7:42:10 | path | lib.js:42:7:42:13 | path[0] | | lib.js:42:7:42:13 | path[0] | lib.js:42:3:42:14 | obj[path[0]] | | lib.js:42:7:42:13 | path[0] | lib.js:42:3:42:14 | obj[path[0]] | @@ -243,7 +245,6 @@ edges | lib.js:83:14:83:22 | arguments | lib.js:83:14:83:25 | arguments[1] | | lib.js:83:14:83:22 | arguments | lib.js:83:14:83:25 | arguments[1] | | lib.js:83:14:83:25 | arguments[1] | lib.js:83:7:83:25 | path | -| lib.js:83:14:83:25 | arguments[1] | lib.js:83:7:83:25 | path | | lib.js:86:7:86:26 | proto | lib.js:87:10:87:14 | proto | | lib.js:86:7:86:26 | proto | lib.js:87:10:87:14 | proto | | lib.js:86:15:86:26 | obj[path[0]] | lib.js:86:7:86:26 | proto | @@ -261,7 +262,6 @@ edges | lib.js:104:13:104:21 | arguments | lib.js:104:13:104:24 | arguments[1] | | lib.js:104:13:104:21 | arguments | lib.js:104:13:104:24 | arguments[1] | | lib.js:104:13:104:24 | arguments[1] | lib.js:104:7:104:24 | one | -| lib.js:104:13:104:24 | arguments[1] | lib.js:104:7:104:24 | one | | lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] | | lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] | | lib.js:118:29:118:32 | path | lib.js:119:17:119:20 | path | @@ -322,16 +322,12 @@ edges | lib.js:6:7:6:9 | obj | lib.js:1:43:1:46 | path | lib.js:6:7:6:9 | obj | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:1:43:1:46 | path | library input | | lib.js:15:3:15:14 | obj[path[0]] | lib.js:14:38:14:41 | path | lib.js:15:3:15:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:14:38:14:41 | path | library input | | lib.js:22:3:22:14 | obj[path[0]] | lib.js:20:14:20:22 | arguments | lib.js:22:3:22:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:20:14:20:22 | arguments | library input | -| lib.js:22:3:22:14 | obj[path[0]] | lib.js:20:14:20:25 | arguments[1] | lib.js:22:3:22:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:20:14:20:25 | arguments[1] | library input | | lib.js:26:10:26:21 | obj[path[0]] | lib.js:25:44:25:47 | path | lib.js:26:10:26:21 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:25:44:25:47 | path | library input | -| lib.js:34:3:34:14 | obj[path[0]] | lib.js:32:14:32:20 | args[1] | lib.js:34:3:34:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:32:14:32:20 | args[1] | library input | +| lib.js:34:3:34:14 | obj[path[0]] | lib.js:30:43:30:51 | arguments | lib.js:34:3:34:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:30:43:30:51 | arguments | library input | | lib.js:42:3:42:14 | obj[path[0]] | lib.js:38:27:38:35 | arguments | lib.js:42:3:42:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:38:27:38:35 | arguments | library input | -| lib.js:42:3:42:14 | obj[path[0]] | lib.js:40:14:40:20 | args[1] | lib.js:42:3:42:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:40:14:40:20 | args[1] | library input | | lib.js:70:13:70:24 | obj[path[0]] | lib.js:59:18:59:18 | s | lib.js:70:13:70:24 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:59:18:59:18 | s | library input | | lib.js:87:10:87:14 | proto | lib.js:83:14:83:22 | arguments | lib.js:87:10:87:14 | proto | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:83:14:83:22 | arguments | library input | -| lib.js:87:10:87:14 | proto | lib.js:83:14:83:25 | arguments[1] | lib.js:87:10:87:14 | proto | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:83:14:83:25 | arguments[1] | library input | | lib.js:108:3:108:10 | obj[one] | lib.js:104:13:104:21 | arguments | lib.js:108:3:108:10 | obj[one] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:104:13:104:21 | arguments | library input | -| lib.js:108:3:108:10 | obj[one] | lib.js:104:13:104:24 | arguments[1] | lib.js:108:3:108:10 | obj[one] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:104:13:104:24 | arguments[1] | library input | | lib.js:119:13:119:24 | obj[path[0]] | lib.js:118:29:118:32 | path | lib.js:119:13:119:24 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:118:29:118:32 | path | library input | | sublib/sub.js:2:3:2:14 | obj[path[0]] | sublib/sub.js:1:37:1:40 | path | sublib/sub.js:2:3:2:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | sublib/sub.js:1:37:1:40 | path | library input | | tst.js:8:5:8:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:8:5:8:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | user controlled input |