From 4cb2145d21ecbdd6d89517a70794e09aef226396 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sat, 25 May 2024 16:33:15 +0100 Subject: [PATCH 1/9] add CWE-770 experimental query for detection of DoS --- ruby/src/security/CWE-770/DoS.qhelp | 39 ++++++ ruby/src/security/CWE-770/DoS.ql | 150 +++++++++++++++++++++ ruby/src/security/CWE-770/examples/bad.rb | 21 +++ ruby/src/security/CWE-770/examples/good.rb | 17 +++ 4 files changed, 227 insertions(+) create mode 100644 ruby/src/security/CWE-770/DoS.qhelp create mode 100644 ruby/src/security/CWE-770/DoS.ql create mode 100644 ruby/src/security/CWE-770/examples/bad.rb create mode 100644 ruby/src/security/CWE-770/examples/good.rb diff --git a/ruby/src/security/CWE-770/DoS.qhelp b/ruby/src/security/CWE-770/DoS.qhelp new file mode 100644 index 00000000..08158bc7 --- /dev/null +++ b/ruby/src/security/CWE-770/DoS.qhelp @@ -0,0 +1,39 @@ + + + + +

When a remote user-controlled data value can be used as part of the limit of times an operation can be executed, such behavior could lead to a denial of service.

+ +
+ + +

Ensure the limitation and the validation of any incoming value to a reasonable value.

+ +
+ + +

+In this example a user-controlled data value such as `1_000` reaches a repeatable operation as `1_000` times. A simple exploit would be for an attacker to send a huge value as `999_999_999` or provoke an endless loop with a negative value. +

+ + + +

To fix this vulnerability, it is required to constrain the size of the user input and validate the incoming value.

+ +

For illustration pureposes, we can limit the possible values for the user input to between `1` and `1_000`.

+ + + +
+ + +
  • + CVE-2022-23837: High severity denial of service vulnerability in Sidekiq, there is no limit on the number of days when requesting stats for the graph. This overloads the system, affecting the Web UI, and makes it unavailable to users. +
  • + +
  • The suggested fix for the Sidekiq denial of service vulnerability.
  • + +
    +
    diff --git a/ruby/src/security/CWE-770/DoS.ql b/ruby/src/security/CWE-770/DoS.ql new file mode 100644 index 00000000..31cbcb72 --- /dev/null +++ b/ruby/src/security/CWE-770/DoS.ql @@ -0,0 +1,150 @@ +/** + * @name Denial of Service using unconstrained integer/float value + * @description A remote user-controlled integer/float value can reach a condition that controls how many times a repeatable operation can be executed. A malicious user may misuse that value to cause an application-level denial of service. + * @kind path-problem + * @id rb/dos + * @precision high + * @problem.severity error + * @tags security + * experimental + * external/cwe/cwe-770 + */ + +import ruby +import codeql.ruby.ApiGraphs +import codeql.ruby.Concepts +import codeql.ruby.TaintTracking +import codeql.ruby.dataflow.RemoteFlowSources +import codeql.ruby.dataflow.BarrierGuards +import codeql.ruby.AST +import codeql.ruby.controlflow.CfgNodes as CfgNodes +import codeql.ruby.CFG +import codeql.ruby.dataflow.internal.DataFlowPublic +import codeql.ruby.InclusionTests + +/** + * Ensure that the user-provided value is limited to a certain amount + * + * @param node The node to check if limited by: + * 1. A comparison operation node with a less than or less than or equal operator + * 2. A comparison operation node with a greater than or greater than or equal operator + * 3. A comparison operation node with a greater than or greater than or equal operator and the branch is false + * 4. A comparison operation node with a less than or less than or equal operator and the branch is false + */ +predicate underAValue(CfgNodes::AstCfgNode g, CfgNode node, boolean branch) { + exists(CfgNodes::ExprNodes::ComparisonOperationCfgNode cn | cn = g | + exists(string op | + ( + // arg <= LIMIT OR arg < LIMIT + (op = "<" or op = "<=") and + branch = true and + op = cn.getOperator() and + node = cn.getLeftOperand() + or + // LIMIT >= arg OR LIMIT > arg + (op = ">" or op = ">=") and + branch = true and + op = cn.getOperator() and + node = cn.getRightOperand() + or + // not arg >= LIMIT OR not arg > LIMIT + (op = ">" or op = ">=") and + branch = false and + op = cn.getOperator() and + node = cn.getLeftOperand() + or + // not LIMIT <= arg OR not LIMIT < argo + (op = "<" or op = "<=") and + branch = false and + op = cn.getOperator() and + node = cn.getRightOperand() + ) + ) + ) +} + +/** + * Sidekiq ensure using the `params` function that all keys in the resulting hash are strings and ingest `request.params`. So a call to `params` function is considered as a remote flow source. + * + * https://github.com/sidekiq/sidekiq/blob/79d254d9045bb5805beed6aaffec1886ef89f71b/lib/sidekiq/web/action.rb#L30-L37 + */ +class ParamsRFS extends RemoteFlowSource::Range { + ParamsRFS() { + exists(ElementReference er, MethodCall mc | + er.getReceiver() = mc and + mc.getMethodName() = "params" and + this.asExpr() = er.getAControlFlowNode() + ) + } + + override string getSourceType() { result = "Request params data" } +} + +private module DoSConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + //source instanceof ParamsRFS or + source instanceof RemoteFlowSource + } + + predicate isBarrier(DataFlow::Node sanitizer) { + // Sanitize the user-provided value if limited (underAValue check) + sanitizer = DataFlow::BarrierGuard::getABarrierNode() + } + + /** + * Support additional flow step for a case like using a default value `(params["days"] | 100).to_i` + */ + predicate isAdditionalFlowStep(DataFlow::Node previousNode, DataFlow::Node nextNode) { + // Additional flow step like `(RFS | INTEGER).to_i` or `(FLOAT | RFS).to_f` + exists(ParenthesizedExpr loe, DataFlow::CallNode c, ExprNode en | + en = c.getReceiver() and + c.getMethodName() = ["to_i", "to_f"] and + c = nextNode and + loe = en.asExpr().getExpr() and + loe.getStmt(_).(LogicalOrExpr).getAnOperand() = previousNode.asExpr().getExpr() and + not previousNode.asExpr().getExpr() instanceof IntegerLiteral + ) + or + // Additional flow step like `RFS.to_i` or `RFS.to_f` + exists(MethodCall mc | + mc.getReceiver() = previousNode.asExpr().getExpr() and + mc.getMethodName() = ["to_i", "to_f"] and + mc = nextNode.asExpr().getExpr() + ) + } + + /** + * - Check if the user-provided value is used in a repeatable operation using `downto`, `upto` or `times` + * - Check if the user-provided value is used in a repeatable operation using `for` loop or conditional loop like `until` or `while`. + */ + predicate isSink(DataFlow::Node sink) { + // sink = n in `100.downto(n)` or `1.upto(n)` + exists(MethodCall mc | + sink.asExpr().getExpr() = mc.getArgument(0) and + mc.getMethodName() = ["downto", "upto"] + ) + or + // sink = n in `n.times()` or `n.downto(1)` or `n.upto(100)` + exists(MethodCall mc | + sink.asExpr().getExpr() = mc.getReceiver() and + mc.getMethodName() = ["times", "downto", "upto"] + ) + or + // sink = 1..n in `for i in 0..n` + exists(ForExpr forLoop | sink.asExpr().getExpr() = forLoop.getValue()) + or + // sink = n in `until n` + exists(ConditionalLoop conditionalLoop | + sink.asExpr().getExpr() = conditionalLoop.getCondition() + ) + } +} + +module DoSFlow = TaintTracking::Global; + +import DoSFlow::PathGraph + +from DoSFlow::PathNode source, DoSFlow::PathNode sink +where DoSFlow::flowPath(source, sink) +select sink.getNode(), source, sink, "This $@ can control $@ a repeatable operation is executed.", + source.getNode(), "user-provided value", sink.getNode(), "how many times" diff --git a/ruby/src/security/CWE-770/examples/bad.rb b/ruby/src/security/CWE-770/examples/bad.rb new file mode 100644 index 00000000..901283f0 --- /dev/null +++ b/ruby/src/security/CWE-770/examples/bad.rb @@ -0,0 +1,21 @@ +class UserController < ActionController::Base + def bad_examples + limit = params[:limit].to_i + + # repeat a simple operation for the number of limit specified using upto() + 1.upto(days) do |i| + put "a repeatable operation" + end + + # repeat a simple operation for the number of limit specified using times() + limit.times do + put "a repeatable operation" + end + + # repeat a simple operation for the number of limit specified using downto() + limit.downto(1) do |i| + put "a repeatable operation" + end + + end +end \ No newline at end of file diff --git a/ruby/src/security/CWE-770/examples/good.rb b/ruby/src/security/CWE-770/examples/good.rb new file mode 100644 index 00000000..455988ca --- /dev/null +++ b/ruby/src/security/CWE-770/examples/good.rb @@ -0,0 +1,17 @@ +class UserController < ActionController::Base + def good_example + limit = params[:limit].to_i + + # limit the limit between 1 and 1000 + if not (limit => 1 && limit < 1000) + limit = 10 + end + + + # repeat a simple operation for the number of limit specified using upto() + 1.upto(days) do |i| + put "a repeatable operation" + end + + end + end \ No newline at end of file From f9cd60de5d4b6d7a3a67cb743d6941f461ca7ad1 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 30 May 2024 16:09:09 +0100 Subject: [PATCH 2/9] Update ruby/src/security/CWE-770/DoS.qhelp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter Stöckli --- ruby/src/security/CWE-770/DoS.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/src/security/CWE-770/DoS.qhelp b/ruby/src/security/CWE-770/DoS.qhelp index 08158bc7..2757cfbc 100644 --- a/ruby/src/security/CWE-770/DoS.qhelp +++ b/ruby/src/security/CWE-770/DoS.qhelp @@ -22,7 +22,7 @@ In this example a user-controlled data value such as `1_000` reaches a repeatabl

    To fix this vulnerability, it is required to constrain the size of the user input and validate the incoming value.

    -

    For illustration pureposes, we can limit the possible values for the user input to between `1` and `1_000`.

    +

    For illustration purposes, we can limit the possible values for the user input to between `1` and `1_000`.

    From d56a0bc7f987b55d5a00c7cfdcd68273d12add24 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 09:30:37 +0100 Subject: [PATCH 3/9] Rename DoS.ql to UserControlledMaxIterations.ql --- .../CWE-770/{DoS.qhelp => UserControlledMaxIterations.qhelp} | 0 .../security/CWE-770/{DoS.ql => UserControlledMaxIterations.ql} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename ruby/src/security/CWE-770/{DoS.qhelp => UserControlledMaxIterations.qhelp} (100%) rename ruby/src/security/CWE-770/{DoS.ql => UserControlledMaxIterations.ql} (99%) diff --git a/ruby/src/security/CWE-770/DoS.qhelp b/ruby/src/security/CWE-770/UserControlledMaxIterations.qhelp similarity index 100% rename from ruby/src/security/CWE-770/DoS.qhelp rename to ruby/src/security/CWE-770/UserControlledMaxIterations.qhelp diff --git a/ruby/src/security/CWE-770/DoS.ql b/ruby/src/security/CWE-770/UserControlledMaxIterations.ql similarity index 99% rename from ruby/src/security/CWE-770/DoS.ql rename to ruby/src/security/CWE-770/UserControlledMaxIterations.ql index 31cbcb72..fa344406 100644 --- a/ruby/src/security/CWE-770/DoS.ql +++ b/ruby/src/security/CWE-770/UserControlledMaxIterations.ql @@ -2,7 +2,7 @@ * @name Denial of Service using unconstrained integer/float value * @description A remote user-controlled integer/float value can reach a condition that controls how many times a repeatable operation can be executed. A malicious user may misuse that value to cause an application-level denial of service. * @kind path-problem - * @id rb/dos + * @id githubsecuritylab/UserControlledMaxIterations * @precision high * @problem.severity error * @tags security From b06ea2bf0ba0f91a61af7b63c0ac79698b22474e Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 09:32:49 +0100 Subject: [PATCH 4/9] Add UserControlledMaxIterations.qlref file for CWE-770 security testing --- ruby/test/security/CWE-770/UserControlledMaxIterations.qlref | 1 + 1 file changed, 1 insertion(+) create mode 100644 ruby/test/security/CWE-770/UserControlledMaxIterations.qlref diff --git a/ruby/test/security/CWE-770/UserControlledMaxIterations.qlref b/ruby/test/security/CWE-770/UserControlledMaxIterations.qlref new file mode 100644 index 00000000..c10d17c5 --- /dev/null +++ b/ruby/test/security/CWE-770/UserControlledMaxIterations.qlref @@ -0,0 +1 @@ +security/CWE-770/UserControlledMaxIterations.ql \ No newline at end of file From 7fa24a41f018863e7a77b517cdc8c2f19dabfcc8 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 09:45:54 +0100 Subject: [PATCH 5/9] add some ruby files for the tests --- .../UserControlledMaxIterations__bad.rb | 21 +++++++++++++++++++ .../UserControlledMaxIterations__good.rb | 17 +++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 ruby/test/security/CWE-770/UserControlledMaxIterations__bad.rb create mode 100644 ruby/test/security/CWE-770/UserControlledMaxIterations__good.rb diff --git a/ruby/test/security/CWE-770/UserControlledMaxIterations__bad.rb b/ruby/test/security/CWE-770/UserControlledMaxIterations__bad.rb new file mode 100644 index 00000000..a1ca68fb --- /dev/null +++ b/ruby/test/security/CWE-770/UserControlledMaxIterations__bad.rb @@ -0,0 +1,21 @@ +class UserController < ActionController::Base + def bad_examples + limit = params[:limit].to_i + + # repeat a simple operation for the number of limit specified using upto() + 1.upto(days) do |i| + put "a repeatable operation" + end + + # repeat a simple operation for the number of limit specified using times() + limit.times do + put "a repeatable operation" + end + + # repeat a simple operation for the number of limit specified using downto() + limit.downto(1) do |i| + put "a repeatable operation" + end + + end + end diff --git a/ruby/test/security/CWE-770/UserControlledMaxIterations__good.rb b/ruby/test/security/CWE-770/UserControlledMaxIterations__good.rb new file mode 100644 index 00000000..455988ca --- /dev/null +++ b/ruby/test/security/CWE-770/UserControlledMaxIterations__good.rb @@ -0,0 +1,17 @@ +class UserController < ActionController::Base + def good_example + limit = params[:limit].to_i + + # limit the limit between 1 and 1000 + if not (limit => 1 && limit < 1000) + limit = 10 + end + + + # repeat a simple operation for the number of limit specified using upto() + 1.upto(days) do |i| + put "a repeatable operation" + end + + end + end \ No newline at end of file From 608efe82265525482f97c7e0e1262d8bd11950f8 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 09:59:50 +0100 Subject: [PATCH 6/9] Add UserControlledMaxIterations.expected file for CWE-770 security testing --- .../UserControlledMaxIterations.expected | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 ruby/test/security/CWE-770/UserControlledMaxIterations.expected diff --git a/ruby/test/security/CWE-770/UserControlledMaxIterations.expected b/ruby/test/security/CWE-770/UserControlledMaxIterations.expected new file mode 100644 index 00000000..c88eeaca --- /dev/null +++ b/ruby/test/security/CWE-770/UserControlledMaxIterations.expected @@ -0,0 +1,19 @@ +edges +| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | +| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | +| UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | +| UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | +| UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | +nodes +| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | semmle.label | limit | +| UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | semmle.label | call to params | +| UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | semmle.label | ...[...] | +| UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | semmle.label | call to to_i | +| UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | semmle.label | limit | +| UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | semmle.label | limit | +subpaths +#select +| UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | This $@ can control $@ a repeatable operation is executed. | UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | user-provided value | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | how many times | +| UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | This $@ can control $@ a repeatable operation is executed. | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | user-provided value | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | how many times | +| UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | This $@ can control $@ a repeatable operation is executed. | UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | user-provided value | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | how many times | +| UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | This $@ can control $@ a repeatable operation is executed. | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | user-provided value | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | how many times | From 0b0d99b3e8bc8e470c5ee78857585f26c8279667 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 14:51:29 +0100 Subject: [PATCH 7/9] Update ruby/src/security/CWE-770/UserControlledMaxIterations.ql MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter Stöckli --- ruby/src/security/CWE-770/UserControlledMaxIterations.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/src/security/CWE-770/UserControlledMaxIterations.ql b/ruby/src/security/CWE-770/UserControlledMaxIterations.ql index fa344406..4a4ebae1 100644 --- a/ruby/src/security/CWE-770/UserControlledMaxIterations.ql +++ b/ruby/src/security/CWE-770/UserControlledMaxIterations.ql @@ -2,7 +2,7 @@ * @name Denial of Service using unconstrained integer/float value * @description A remote user-controlled integer/float value can reach a condition that controls how many times a repeatable operation can be executed. A malicious user may misuse that value to cause an application-level denial of service. * @kind path-problem - * @id githubsecuritylab/UserControlledMaxIterations + * @id githubsecuritylab/user-controlled-max-iterations * @precision high * @problem.severity error * @tags security From 7b2414266cb4605f5b71ae43e69a102a98123839 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 4 Jun 2024 14:52:05 +0100 Subject: [PATCH 8/9] chore: Remove unused Ruby files for CWE-770 examples --- ruby/src/security/CWE-770/examples/bad.rb | 21 --------------------- ruby/src/security/CWE-770/examples/good.rb | 17 ----------------- 2 files changed, 38 deletions(-) delete mode 100644 ruby/src/security/CWE-770/examples/bad.rb delete mode 100644 ruby/src/security/CWE-770/examples/good.rb diff --git a/ruby/src/security/CWE-770/examples/bad.rb b/ruby/src/security/CWE-770/examples/bad.rb deleted file mode 100644 index 901283f0..00000000 --- a/ruby/src/security/CWE-770/examples/bad.rb +++ /dev/null @@ -1,21 +0,0 @@ -class UserController < ActionController::Base - def bad_examples - limit = params[:limit].to_i - - # repeat a simple operation for the number of limit specified using upto() - 1.upto(days) do |i| - put "a repeatable operation" - end - - # repeat a simple operation for the number of limit specified using times() - limit.times do - put "a repeatable operation" - end - - # repeat a simple operation for the number of limit specified using downto() - limit.downto(1) do |i| - put "a repeatable operation" - end - - end -end \ No newline at end of file diff --git a/ruby/src/security/CWE-770/examples/good.rb b/ruby/src/security/CWE-770/examples/good.rb deleted file mode 100644 index 455988ca..00000000 --- a/ruby/src/security/CWE-770/examples/good.rb +++ /dev/null @@ -1,17 +0,0 @@ -class UserController < ActionController::Base - def good_example - limit = params[:limit].to_i - - # limit the limit between 1 and 1000 - if not (limit => 1 && limit < 1000) - limit = 10 - end - - - # repeat a simple operation for the number of limit specified using upto() - 1.upto(days) do |i| - put "a repeatable operation" - end - - end - end \ No newline at end of file From 757cf0512bf1bb00b965e6d98013467c606745d0 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 5 Jun 2024 22:58:41 +0100 Subject: [PATCH 9/9] added " provenance | |" to fix the expected test file --- .../CWE-770/UserControlledMaxIterations.expected | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ruby/test/security/CWE-770/UserControlledMaxIterations.expected b/ruby/test/security/CWE-770/UserControlledMaxIterations.expected index c88eeaca..9567b8db 100644 --- a/ruby/test/security/CWE-770/UserControlledMaxIterations.expected +++ b/ruby/test/security/CWE-770/UserControlledMaxIterations.expected @@ -1,9 +1,9 @@ edges -| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | -| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | -| UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | -| UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | -| UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | +| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:11:7:11:11 | limit | provenance | | +| UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | UserControlledMaxIterations__bad.rb:16:7:16:11 | limit | provenance | | +| UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | provenance | | +| UserControlledMaxIterations__bad.rb:3:15:3:28 | ...[...] | UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | provenance | | +| UserControlledMaxIterations__bad.rb:3:15:3:33 | call to to_i | UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | provenance | | nodes | UserControlledMaxIterations__bad.rb:3:7:3:11 | limit | semmle.label | limit | | UserControlledMaxIterations__bad.rb:3:15:3:20 | call to params | semmle.label | call to params |