diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index b89d7b1bdda..cc2297365b6 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -41,6 +41,7 @@ | Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | | Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 5eb02bc148b..65bea14986e 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -44,6 +44,7 @@ + semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730 + semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754 + semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770 ++ semmlecode-javascript-queries/Security/CWE-770/ResourceExhaustion.ql: /Security/CWE/CWE-770 + semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776 + semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798 + semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807 diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp new file mode 100644 index 00000000000..7ffd054945e --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -0,0 +1,113 @@ + + + + + +

+ + Applications are constrained by how many resources they can make use + of. Failing to respect these constraints may cause the application to + be unresponsive or crash. It is therefore problematic if attackers + can control the sizes or lifetimes of allocated objects. + +

+ +
+ + + +

+ + Ensure that attackers can not control object sizes and their + lifetimes. If object sizes and lifetimes must be controlled by + external parties, ensure you restrict the object sizes and lifetimes so that + they are within acceptable ranges. + +

+ +
+ + + +

+ + The following example allocates a buffer with a user-controlled + size. + +

+ + + +

+ + This is problematic since an attacker can choose a size + that makes the application run out of memory. Even worse, in older + versions of Node.js, this could leak confidential memory. + + To prevent such attacks, limit the buffer size: + +

+ + + +
+ + + +

+ + As another example, consider an application that allocates an + array with a user-controlled size, and then fills it with values: + +

+ + + +

+ The allocation of the array itself is not problematic since arrays are + allocated sparsely, but the subsequent filling of the array will take + a long time, causing the application to be unresponsive, or even run + out of memory. + + Again, a limit on the size will prevent the attack: + +

+ + + +
+ + + +

+ + Finally, the following example lets a user choose a delay after + which a function is executed: + +

+ + + +

+ + This is problematic because a large delay essentially makes the + application wait indefinitely before executing the function. Repeated + registrations of such delays will therefore use up all of the memory + in the application. + + Again, a limit on the delay will prevent the attack: + +

+ + + + +
+ + + + + +
diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql new file mode 100644 index 00000000000..adb8663085e --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql @@ -0,0 +1,20 @@ +/** + * @name Resource exhaustion + * @description Allocating objects or timers with user-controlled + * sizes or durations can cause resource exhaustion. + * @kind path-problem + * @problem.severity warning + * @id js/resource-exhaustion + * @precision high + * @tags security + * external/cwe/cwe-770 + */ + +import javascript +import DataFlow::PathGraph +import semmle.javascript.security.dataflow.ResourceExhaustion::ResourceExhaustion + +from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink +where dataflow.hasFlowPath(source, sink) +select sink, source, sink, sink.getNode().(Sink).getProblemDescription() + " from $@.", source, + "here" diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js new file mode 100644 index 00000000000..e7c6be16953 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let dogs = new Array(size).fill(x => "dog"); // BAD + + // ... use the dogs +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js new file mode 100644 index 00000000000..f7c88129264 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let dogs = new Array(size).fill(x => "dog"); // GOOD + + // ... use the dogs +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js new file mode 100644 index 00000000000..d821901e818 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let buffer = Buffer.alloc(size); // BAD + + // ... use the buffer +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js new file mode 100644 index 00000000000..8d9f9b0839f --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let buffer = Buffer.alloc(size); // GOOD + + // ... use the buffer +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js new file mode 100644 index 00000000000..1718509534b --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js @@ -0,0 +1,9 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + setTimeout(f, delay); // BAD + +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js new file mode 100644 index 00000000000..2f5a614e3d7 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js @@ -0,0 +1,15 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + if (delay > 1000) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + setTimeout(f, delay); // GOOD + +}); diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll new file mode 100644 index 00000000000..dc46eb7daf0 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll @@ -0,0 +1,77 @@ +/** + * Provides a taint tracking configuration for reasoning about + * resource exhaustion vulnerabilities (CWE-770). + * + * Note, for performance reasons: only import this file if + * `ResourceExhaustion::Configuration` is needed, otherwise + * `ResourceExhaustionCustomizations` should be imported instead. + */ + +import javascript +import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations + +module ResourceExhaustion { + import ResourceExhaustionCustomizations::ResourceExhaustion + + /** + * A data flow configuration for resource exhaustion vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "ResourceExhaustion" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source.(Source).getAFlowLabel() = label + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink.(Sink).getAFlowLabel() = label + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, + DataFlow::FlowLabel dstlabel + ) { + dstlabel instanceof Label::Number and + isNumericFlowStep(src, dst) + or + // reuse most existing taint steps + super.isAdditionalFlowStep(src, dst) and + not dst.asExpr() instanceof AddExpr and + if dst.(DataFlow::MethodCallNode).calls(src, "toString") + then dstlabel.isTaint() + else srclabel = dstlabel + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or + guard instanceof UpperBoundsCheckSanitizerGuard or + guard instanceof TypeTestGuard + } + } + + /** + * Holds if data may flow from `src` to `dst` as a number. + */ + predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) { + // steps that introduce or preserve a number + dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) + or + exists(DataFlow::CallNode c | + c = dst and + src = c.getAnArgument() + | + c = DataFlow::globalVarRef("Math").getAMemberCall(_) or + c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() + ) + or + exists(Expr dstExpr, Expr srcExpr | + dstExpr = dst.asExpr() and + srcExpr = src.asExpr() + | + dstExpr.(BinaryExpr).getAnOperand() = srcExpr and + not dstExpr instanceof AddExpr + or + dstExpr.(PlusExpr).getOperand() = srcExpr + ) + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll new file mode 100644 index 00000000000..7363474478d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll @@ -0,0 +1,187 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * resource exhaustion vulnerabilities, as well as extension points for + * adding your own. + */ + +import javascript + +module ResourceExhaustion { + /** + * A data flow source for resource exhaustion vulnerabilities. + */ + abstract class Source extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a source. */ + DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } + } + + /** + * A data flow sink for resource exhaustion vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a sink. */ + DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number } + + /** + * Gets a description of why this is a problematic sink. + */ + abstract string getProblemDescription(); + } + + /** + * A data flow sanitizer for resource exhaustion vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * Provides data flow labels for resource exhaustion vulnerabilities. + */ + module Label { + /** + * A number data flow label. + */ + class Number extends DataFlow::FlowLabel { + Number() { this = "number" } + } + } + + /** + * A sanitizer that blocks taint flow if the size of a number is limited. + */ + class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override RelationalComparison astNode; + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + label instanceof Label::Number and + ( + true = outcome and + e = astNode.getLesserOperand() + or + false = outcome and + e = astNode.getGreaterOperand() + ) + } + } + + /** + * A test of form `typeof x === "something"`, preventing `x` from being a number in some cases. + */ + class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + TypeofExpr typeof; + boolean polarity; + + TypeTestGuard() { + astNode.getAnOperand() = typeof and + ( + // typeof x === "number" sanitizes `x` when it evaluates to false + astNode.getAnOperand().getStringValue() = "number" and + polarity = astNode.getPolarity().booleanNot() + or + // typeof x === "string" sanitizes `x` when it evaluates to true + astNode.getAnOperand().getStringValue() != "number" and + polarity = astNode.getPolarity() + ) + } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + polarity = outcome and + e = typeof.getOperand() and + label instanceof Label::Number + } + } + + /** A source of remote user input, considered as a data flow source for resource exhaustion vulnerabilities. */ + class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + } + + /** + * A node that determines the size of a buffer, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class BufferSizeSink extends Sink { + BufferSizeSink() { + exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | + clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) + | + exists(string name | + invk = clazz.getAMemberCall(name) and + ( + name = "from" and index = 2 + or + name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 + ) + ) + or + invk = clazz.getAnInvocation() and + ( + invk.getNumArgument() = 1 and + index = 0 + or + invk.getNumArgument() = 3 and index = 2 + ) + ) + or + this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) + } + + override string getProblemDescription() { + result = "This creates a buffer with a user-controlled size" + } + } + + /** + * A node that determines the size of an array, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class DenseArraySizeSink extends Sink { + DenseArraySizeSink() { + // Arrays are sparse by default, so we must also look at how the array is used + exists(DataFlow::ArrayConstructorInvokeNode instance | + this = instance.getArgument(0) and + instance.getNumArgument() = 1 + | + exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or + instance.flowsToExpr(any(AddExpr p).getAnOperand()) + ) + } + + override string getProblemDescription() { + result = "This creates an array with a user-controlled length" + } + } + + /** + * A node that determines the repetitions of a string, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class StringRepetitionSink extends Sink { + StringRepetitionSink() { + exists(DataFlow::MethodCallNode repeat | + repeat.getMethodName() = "repeat" and + this = repeat.getArgument(0) + ) + } + + override DataFlow::FlowLabel getAFlowLabel() { any() } + + override string getProblemDescription() { + result = "This creates a string with a user-controlled length" + } + } + + /** + * A node that determines the duration of a timer, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class TimerDurationSink extends Sink { + TimerDurationSink() { + this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) or + this = LodashUnderscore::member(["delay", "throttle", "debounce"]).getACall().getArgument(1) + } + + override DataFlow::FlowLabel getAFlowLabel() { any() } + + override string getProblemDescription() { + result = "This creates a timer with a user-controlled duration" + } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected new file mode 100644 index 00000000000..0260567be53 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected @@ -0,0 +1,234 @@ +nodes +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| resource-exhaustion.js:5:7:5:42 | s | +| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | +| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | +| resource-exhaustion.js:5:21:5:27 | req.url | +| resource-exhaustion.js:5:21:5:27 | req.url | +| resource-exhaustion.js:6:7:6:21 | n | +| resource-exhaustion.js:6:11:6:21 | parseInt(s) | +| resource-exhaustion.js:6:20:6:20 | s | +| resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:37:14:37:14 | n | +| resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:24:45:24 | s | +| resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:21:46:21 | s | +| resource-exhaustion.js:50:14:50:14 | s | +| resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:58:7:58:20 | ns | +| resource-exhaustion.js:58:12:58:20 | x ? n : s | +| resource-exhaustion.js:58:16:58:16 | n | +| resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:84:18:84:18 | s | +edges +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:6:20:6:20 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:45:24:45:24 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:46:21:46:21 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:50:14:50:14 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | resource-exhaustion.js:5:11:5:40 | url.par ... ).query | +| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | resource-exhaustion.js:5:11:5:42 | url.par ... query.s | +| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | resource-exhaustion.js:5:7:5:42 | s | +| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:37:14:37:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:58:16:58:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:6:11:6:21 | parseInt(s) | resource-exhaustion.js:6:7:6:21 | n | +| resource-exhaustion.js:6:20:6:20 | s | resource-exhaustion.js:6:11:6:21 | parseInt(s) | +| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:58:12:58:20 | x ? n : s | resource-exhaustion.js:58:7:58:20 | ns | +| resource-exhaustion.js:58:16:58:16 | n | resource-exhaustion.js:58:12:58:20 | x ? n : s | +#select +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | This creates an array with a user-controlled length from $@. | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | here | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | This creates a buffer with a user-controlled size from $@. | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | here | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | This creates a timer with a user-controlled duration from $@. | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | here | +| resource-exhaustion.js:12:21:12:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:12:21:12:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:13:21:13:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:13:21:13:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:14:16:14:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:14:16:14:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:15:22:15:22 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:15:22:15:22 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:16:26:16:26 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:16:26:16:26 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:18:14:18:14 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:18:14:18:14 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:20:20:20:20 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:20:20:20:20 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:22:18:22:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:22:18:22:18 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:27:9:27:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:27:9:27:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:28:13:28:13 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:28:13:28:13 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:29:9:29:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:29:9:29:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:30:9:30:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:30:9:30:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:31:9:31:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:31:9:31:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:32:9:32:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:32:9:32:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:34:12:34:12 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:34:12:34:12 | n | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:35:12:35:12 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:35:12:35:12 | s | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:37:14:37:18 | n * x | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:37:14:37:18 | n * x | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:46:14:46:22 | Number(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:46:14:46:22 | Number(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:50:14:50:21 | s.length | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:50:14:50:21 | s.length | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:55:16:55:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:55:16:55:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:59:14:59:15 | ns | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:59:14:59:15 | ns | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:66:16:66:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:66:16:66:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:70:16:70:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:70:16:70:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:81:17:81:17 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:81:17:81:17 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:82:17:82:17 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:82:17:82:17 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:83:18:83:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:83:18:83:18 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:84:18:84:18 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:84:18:84:18 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref new file mode 100644 index 00000000000..38e612d406f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref @@ -0,0 +1 @@ +Security/CWE-770/ResourceExhaustion.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js new file mode 100644 index 00000000000..2fad9da5d93 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let dogs = new Array(size).fill(x => "dog"); // BAD + + // ... use the dog +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js new file mode 100644 index 00000000000..f7c88129264 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let dogs = new Array(size).fill(x => "dog"); // GOOD + + // ... use the dogs +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js new file mode 100644 index 00000000000..d821901e818 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let buffer = Buffer.alloc(size); // BAD + + // ... use the buffer +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js new file mode 100644 index 00000000000..8d9f9b0839f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let buffer = Buffer.alloc(size); // GOOD + + // ... use the buffer +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js new file mode 100644 index 00000000000..1718509534b --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js @@ -0,0 +1,9 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + setTimeout(f, delay); // BAD + +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js new file mode 100644 index 00000000000..2f5a614e3d7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js @@ -0,0 +1,15 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + if (delay > 1000) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + setTimeout(f, delay); // GOOD + +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js new file mode 100644 index 00000000000..1500fe15b87 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js @@ -0,0 +1,85 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + let s = url.parse(req.url, true).query.s; + let n = parseInt(s); + + Buffer.from(s); // OK + Buffer.from(n); // OK + Buffer.from(x, n); // OK + Buffer.from(x, y, s); // NOT OK + Buffer.from(x, y, n); // NOT OK + Buffer.from(x, y, n); // NOT OK + Buffer.alloc(n); // NOT OK + Buffer.allocUnsafe(n); // NOT OK + Buffer.allocUnsafeSlow(n); // NOT OK + + new Buffer(n); // NOT OK + new Buffer(x, n); // OK + new Buffer(x, y, n); // NOT OK + + new SlowBuffer(n); // NOT OK + + Array(n); // OK + new Array(n); // OK + + Array(n).map(); // NOT OK + new Array(n).map(); // NOT OK + Array(n).fill(); // NOT OK + Array(n).join(); // NOT OK + Array(n).toString(); // NOT OK + Array(n) + x; // NOT OK + + x.repeat(n); // NOT OK + x.repeat(s); // NOT OK + + new Buffer(n * x); // NOT OK + new Buffer(n + n); // NOT OK [INCONSISTENCY] + new Buffer(n + x); // OK (maybe) + new Buffer(n + s); // OK (this is a string if `s` is a string) + new Buffer(s + 2); // OK (this is a string if `s` is a string) + new Buffer(s + s); // OK + new Buffer(n + "X"); // OK + + new Buffer(Math.ceil(s)); // NOT OK + new Buffer(Number(s)); // NOT OK + new Buffer(new Number(s)); // OK + + new Buffer(s + x.length); // OK (this is a string if `s` is a string) + new Buffer(s.length); // NOT OK + + if (n < 100) { + new Buffer(n); // OK + } else { + new Buffer(n); // NOT OK + } + + let ns = x ? n : s; + new Buffer(ns); // NOT OK + + new Buffer(n.toString()); // OK + + if (typeof n === "string") { + new Buffer(n); // OK + } else { + new Buffer(n); // NOT OK + } + + if (typeof n === "number") { + new Buffer(n); // NOT OK + } else { + new Buffer(n); // OK + } + + if (typeof s === "number") { + new Buffer(s); // NOT OK [INCONSISTENCY] + } else { + new Buffer(s); // OK + } + + setTimeout(f, n); // NOT OK + setTimeout(f, s); // NOT OK + setInterval(f, n); // NOT OK + setInterval(f, s); // NOT OK +});