From 4b36a62834692e37b3af3be4dce2434a566fb292 Mon Sep 17 00:00:00 2001
From: Your Name
Date: Sun, 3 Jan 2021 00:51:34 +0300
Subject: [PATCH 01/12] divide by zero rule
---
.../experimental/CWE-369/DivideByZero.qhelp | 23 ++++++++
ql/src/experimental/CWE-369/DivideByZero.ql | 57 +++++++++++++++++++
.../experimental/CWE-369/DivideByZeroBad.go | 19 +++++++
3 files changed, 99 insertions(+)
create mode 100644 ql/src/experimental/CWE-369/DivideByZero.qhelp
create mode 100644 ql/src/experimental/CWE-369/DivideByZero.ql
create mode 100644 ql/src/experimental/CWE-369/DivideByZeroBad.go
diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp
new file mode 100644
index 00000000000..c2b4d546866
--- /dev/null
+++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp
@@ -0,0 +1,23 @@
+
+
+
+
+ Divide by zero is division where the divisor (denominator) is zero.
+ In Golang language, integer divide by zero leads to panic(), which might interrupt execution of the program and lead to program termination.
+
+
+
+
+ Every user input should be checked for correctness, if needed.
+ In case of divide by zero, comparison with zero should be added. It is also possible to handle panic(),
+ generated by division by zero, by built-in function recover().
+
+
+
+
+The following example shows simplified case, when data received from user input, which is used as a divisor and
+causes divide by zero with panic signal.
+
+
+
+
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
new file mode 100644
index 00000000000..7670f3a5dae
--- /dev/null
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -0,0 +1,57 @@
+/**
+ * @name Divide by zero
+ * @description Converting the result of `strconv.Atoi`, `strconv.ParseInt`,
+ * and `strconv.ParseUint` to integer types or use of integer types for division without checks
+ * might lead to division by zero and panic, which cause denial of service.
+ * @kind path-problem
+ * @problem.severity error
+ * @id go/divide-by-zero
+ * @tags security
+ * external/cwe/cwe-369
+ */
+
+import go
+import DataFlow::PathGraph
+
+class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
+ override predicate checks(Expr e, boolean branch) {
+ exists(DataFlow::Node zero, DataFlow::Node sink |
+ zero.getNumericValue() = 0 and
+ sink.getType().getUnderlyingType() instanceof SignedIntegerType and
+ this.eq(branch.booleanNot(), sink, zero) and
+ globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink)
+ )
+ }
+}
+
+class DivideByZeroCheckConfig extends TaintTracking::Configuration {
+ DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ exists(DataFlow::CallNode c, IntegerParser::Range ip |
+ c.getTarget() = ip and source = c.getResult(0)
+ )
+ or
+ exists(IntegerType integerType | source.getType().getUnderlyingType() = integerType)
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(IntegerType integerType, QuoExpr e |
+ sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand() and
+ not sink.asExpr().getParent().(QuoExpr).getRightOperand().isConst() and
+ sink.getType().getUnderlyingType() = integerType
+ )
+ }
+
+ override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
+ guard instanceof DivideByZeroSanitizeGuard
+ }
+}
+
+from
+ DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg,
+ DataFlow::CallNode call
+where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode()
+select sink, source, sink,
+ "Variable $@, which is used at division statement might be zero and leads to division by zero exception.",
+ sink, sink.getNode().toString()
\ No newline at end of file
diff --git a/ql/src/experimental/CWE-369/DivideByZeroBad.go b/ql/src/experimental/CWE-369/DivideByZeroBad.go
new file mode 100644
index 00000000000..be70aca3f8f
--- /dev/null
+++ b/ql/src/experimental/CWE-369/DivideByZeroBad.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+func main() {
+ if len(os.Args) < 2 {
+ fmt.Printf("Usage: ./program value\n")
+ return
+ }
+ val1 := 1337
+ value, _ := strconv.Atoi(os.Args[1])
+ out := val1 / value
+ fmt.Println(out)
+ return
+}
\ No newline at end of file
From d81ec159900a2192574754f800205022f7124cbf Mon Sep 17 00:00:00 2001
From: monkey-junkie
Date: Sun, 3 Jan 2021 00:54:42 +0300
Subject: [PATCH 02/12] Update DivideByZeroBad.go
---
ql/src/experimental/CWE-369/DivideByZeroBad.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZeroBad.go b/ql/src/experimental/CWE-369/DivideByZeroBad.go
index be70aca3f8f..cb943aa82b8 100644
--- a/ql/src/experimental/CWE-369/DivideByZeroBad.go
+++ b/ql/src/experimental/CWE-369/DivideByZeroBad.go
@@ -16,4 +16,4 @@ func main() {
out := val1 / value
fmt.Println(out)
return
-}
\ No newline at end of file
+}
From de566da91c9b677bea76ca543972263fed878af5 Mon Sep 17 00:00:00 2001
From: monkey-junkie
Date: Sun, 3 Jan 2021 00:55:10 +0300
Subject: [PATCH 03/12] Update DivideByZero.ql
---
ql/src/experimental/CWE-369/DivideByZero.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 7670f3a5dae..741f0155195 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -54,4 +54,4 @@ from
where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode()
select sink, source, sink,
"Variable $@, which is used at division statement might be zero and leads to division by zero exception.",
- sink, sink.getNode().toString()
\ No newline at end of file
+ sink, sink.getNode().toString()
From 3251fb5c07047218ff0be7d306cb4560dd27f7d2 Mon Sep 17 00:00:00 2001
From: Your Name
Date: Mon, 18 Jan 2021 02:37:53 +0300
Subject: [PATCH 04/12] updated
---
ql/src/experimental/CWE-369/DivideByZero.ql | 50 ++++++++++++---------
1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 741f0155195..a7a16b2f9c5 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -12,13 +12,23 @@
import go
import DataFlow::PathGraph
+import semmle.go.dataflow.internal.TaintTrackingUtil
-class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
+class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
override predicate checks(Expr e, boolean branch) {
- exists(DataFlow::Node zero, DataFlow::Node sink |
+ exists(
+ DataFlow::Node zero, DataFlow::Node sink, DataFlow::EqualityTestNode eqNode,
+ DataFlow::RelationalComparisonNode compNode
+ |
zero.getNumericValue() = 0 and
- sink.getType().getUnderlyingType() instanceof SignedIntegerType and
- this.eq(branch.booleanNot(), sink, zero) and
+ (
+ sink.getType().getUnderlyingType() instanceof SignedIntegerType or
+ sink.getType().getUnderlyingType() instanceof UnsignedIntegerType
+ ) and
+ (
+ eqNode.eq(branch.booleanNot(), sink, zero) or
+ compNode.leq(branch.booleanNot(), sink, zero, 0)
+ ) and
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink)
)
}
@@ -27,31 +37,31 @@ class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::Equali
class DivideByZeroCheckConfig extends TaintTracking::Configuration {
DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" }
- override predicate isSource(DataFlow::Node source) {
- exists(DataFlow::CallNode c, IntegerParser::Range ip |
- c.getTarget() = ip and source = c.getResult(0)
- )
- or
- exists(IntegerType integerType | source.getType().getUnderlyingType() = integerType)
- }
+ override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
- override predicate isSink(DataFlow::Node sink) {
- exists(IntegerType integerType, QuoExpr e |
- sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand() and
- not sink.asExpr().getParent().(QuoExpr).getRightOperand().isConst() and
- sink.getType().getUnderlyingType() = integerType
+ override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
+ exists(Function f |
+ (
+ f.getName() = "Atoi" or
+ f.getName() = "ParseInt" or
+ f.getName() = "ParseUint"
+ ) and
+ node1 = f.getACall().getArgument(0) and
+ node2 = f.getACall().getResult(0)
)
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof DivideByZeroSanitizeGuard
}
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(QuoExpr e | sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand())
+ }
}
-from
- DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg,
- DataFlow::CallNode call
-where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode()
+from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg
+where cfg.hasFlowPath(source, sink)
select sink, source, sink,
"Variable $@, which is used at division statement might be zero and leads to division by zero exception.",
sink, sink.getNode().toString()
From c8da633d7be0a902ada454a8524733e1cce3f892 Mon Sep 17 00:00:00 2001
From: monkey-junkie
Date: Thu, 21 Jan 2021 00:54:00 +0300
Subject: [PATCH 05/12] Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
---
ql/src/experimental/CWE-369/DivideByZero.ql | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index a7a16b2f9c5..cb147b8f48a 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -22,8 +22,7 @@ class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
|
zero.getNumericValue() = 0 and
(
- sink.getType().getUnderlyingType() instanceof SignedIntegerType or
- sink.getType().getUnderlyingType() instanceof UnsignedIntegerType
+ sink.getType().getUnderlyingType() instanceof IntegerType
) and
(
eqNode.eq(branch.booleanNot(), sink, zero) or
From ad22445d1630a20d158b4ff1b8b9c20222568ff2 Mon Sep 17 00:00:00 2001
From: Your Name
Date: Thu, 21 Jan 2021 01:52:00 +0300
Subject: [PATCH 06/12] refactor
---
ql/src/experimental/CWE-369/DivideByZero.ql | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index cb147b8f48a..23cbd206578 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -17,18 +17,17 @@ import semmle.go.dataflow.internal.TaintTrackingUtil
class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
override predicate checks(Expr e, boolean branch) {
exists(
- DataFlow::Node zero, DataFlow::Node sink, DataFlow::EqualityTestNode eqNode,
+ DataFlow::Node zero, DataFlow::Node checked, DataFlow::EqualityTestNode eqNode,
DataFlow::RelationalComparisonNode compNode
|
zero.getNumericValue() = 0 and
(
- sink.getType().getUnderlyingType() instanceof IntegerType
+ checked.getType().getUnderlyingType() instanceof IntegerType
) and
(
- eqNode.eq(branch.booleanNot(), sink, zero) or
- compNode.leq(branch.booleanNot(), sink, zero, 0)
- ) and
- globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink)
+ this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
+ this.(RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
+ )
)
}
}
@@ -41,9 +40,9 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(Function f |
(
- f.getName() = "Atoi" or
- f.getName() = "ParseInt" or
- f.getName() = "ParseUint"
+ f.hasQualifiedName() = "Atoi" or
+ f.hasQualifiedName() = "ParseInt" or
+ f.hasQualifiedName() = "ParseUint"
) and
node1 = f.getACall().getArgument(0) and
node2 = f.getACall().getResult(0)
From a77f36fba850eee1ed43ce28e1dcfee63df4b95d Mon Sep 17 00:00:00 2001
From: Your Name
Date: Thu, 21 Jan 2021 01:57:19 +0300
Subject: [PATCH 07/12] formatting fix
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
---
ql/src/experimental/CWE-369/DivideByZero.ql | 31 +++++++++++----------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 23cbd206578..314f2f8a9a1 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -15,20 +15,23 @@ import DataFlow::PathGraph
import semmle.go.dataflow.internal.TaintTrackingUtil
class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
+
+ DivideByZeroSanitizeGuard() {
+ this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or
+ this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0
+ }
+
override predicate checks(Expr e, boolean branch) {
- exists(
- DataFlow::Node zero, DataFlow::Node checked, DataFlow::EqualityTestNode eqNode,
- DataFlow::RelationalComparisonNode compNode
- |
- zero.getNumericValue() = 0 and
- (
- checked.getType().getUnderlyingType() instanceof IntegerType
- ) and
- (
- this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
- this.(RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
+ exists(DataFlow::Node zero, DataFlow::Node checked
+ |
+ zero.getNumericValue() = 0 and
+ e = checked.asExpr() and
+ checked.getType().getUnderlyingType() instanceof IntegerType and
+ (
+ this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
+ this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
+ )
)
- )
}
}
@@ -40,9 +43,7 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(Function f |
(
- f.hasQualifiedName() = "Atoi" or
- f.hasQualifiedName() = "ParseInt" or
- f.hasQualifiedName() = "ParseUint"
+ f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"])
) and
node1 = f.getACall().getArgument(0) and
node2 = f.getACall().getResult(0)
From 41e808dab43f27945e549475f9a2e1a6ae6ed8fc Mon Sep 17 00:00:00 2001
From: Your Name
Date: Mon, 25 Jan 2021 03:40:26 +0300
Subject: [PATCH 08/12] conversion detect + tests
---
ql/src/experimental/CWE-369/DivideByZero.ql | 27 ++++++++++---------
.../CWE-369/DivideByZero.expected | 13 +++++++++
ql/test/experimental/CWE-369/DivideByZero.go | 21 +++++++++++++++
.../experimental/CWE-369/DivideByZero.qlref | 1 +
4 files changed, 49 insertions(+), 13 deletions(-)
create mode 100644 ql/test/experimental/CWE-369/DivideByZero.expected
create mode 100644 ql/test/experimental/CWE-369/DivideByZero.go
create mode 100644 ql/test/experimental/CWE-369/DivideByZero.qlref
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 314f2f8a9a1..389f49f262a 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -15,23 +15,21 @@ import DataFlow::PathGraph
import semmle.go.dataflow.internal.TaintTrackingUtil
class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
-
DivideByZeroSanitizeGuard() {
this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or
this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0
}
override predicate checks(Expr e, boolean branch) {
- exists(DataFlow::Node zero, DataFlow::Node checked
- |
- zero.getNumericValue() = 0 and
- e = checked.asExpr() and
- checked.getType().getUnderlyingType() instanceof IntegerType and
- (
- this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
- this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
- )
+ exists(DataFlow::Node zero, DataFlow::Node checked |
+ zero.getNumericValue() = 0 and
+ e = checked.asExpr() and
+ checked.getType().getUnderlyingType() instanceof IntegerType and
+ (
+ this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
+ this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
)
+ )
}
}
@@ -42,12 +40,15 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(Function f |
- (
- f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"])
- ) and
+ f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and
node1 = f.getACall().getArgument(0) and
node2 = f.getACall().getResult(0)
)
+ or
+ exists(ConversionExpr ce | ce.getType().getUnderlyingType() instanceof IntegerType |
+ node1.asExpr() = ce.getOperand() and
+ node2.asExpr() = ce.getAChildExpr()
+ )
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected
new file mode 100644
index 00000000000..85d634ae3c0
--- /dev/null
+++ b/ql/test/experimental/CWE-369/DivideByZero.expected
@@ -0,0 +1,13 @@
+edges
+| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value |
+| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:752:11:752:24 | type conversion : uint8 |
+| DivideByZero.go:752:11:752:24 | type conversion : uint8 | DivideByZero.go:753:16:753:20 | value |
+nodes
+| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:745:16:745:20 | value | semmle.label | value |
+| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:752:11:752:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
+| DivideByZero.go:753:16:753:20 | value | semmle.label | value |
+#select
+| DivideByZero.go:745:16:745:20 | value | DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:745:16:745:20 | value | value |
+| DivideByZero.go:753:16:753:20 | value | DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:753:16:753:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:753:16:753:20 | value | value |
\ No newline at end of file
diff --git a/ql/test/experimental/CWE-369/DivideByZero.go b/ql/test/experimental/CWE-369/DivideByZero.go
new file mode 100644
index 00000000000..575d23504f3
--- /dev/null
+++ b/ql/test/experimental/CWE-369/DivideByZero.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "strconv"
+)
+
+func myHandler1(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.Atoi(param1)
+ out := 1337 / value
+ fmt.Println(out)
+}
+
+func myHandler2(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value := int(param1[0])
+ out := 1337 / value
+ fmt.Println(out)
+}
diff --git a/ql/test/experimental/CWE-369/DivideByZero.qlref b/ql/test/experimental/CWE-369/DivideByZero.qlref
new file mode 100644
index 00000000000..6aae6de95d7
--- /dev/null
+++ b/ql/test/experimental/CWE-369/DivideByZero.qlref
@@ -0,0 +1 @@
+experimental/CWE-369/DivideByZero.ql
From 8c5e0a42b396e310b50a0612e7e8a189e220a5b5 Mon Sep 17 00:00:00 2001
From: Your Name
Date: Tue, 26 Jan 2021 03:07:36 +0300
Subject: [PATCH 09/12] test fixed
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
---
ql/src/experimental/CWE-369/DivideByZero.ql | 6 +++---
.../CWE-369/DivideByZero.expected | 20 +++++++++----------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 389f49f262a..4fde3b6164b 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -14,7 +14,7 @@ import go
import DataFlow::PathGraph
import semmle.go.dataflow.internal.TaintTrackingUtil
-class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard {
+class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard {
DivideByZeroSanitizeGuard() {
this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or
this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0
@@ -38,7 +38,7 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
- override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
+ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Function f |
f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and
node1 = f.getACall().getArgument(0) and
@@ -63,5 +63,5 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg
where cfg.hasFlowPath(source, sink)
select sink, source, sink,
- "Variable $@, which is used at division statement might be zero and leads to division by zero exception.",
+ "Variable $@, which is used at division statement might be zero leading to a division-by-zero panic.",
sink, sink.getNode().toString()
diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected
index 85d634ae3c0..0d22d93159d 100644
--- a/ql/test/experimental/CWE-369/DivideByZero.expected
+++ b/ql/test/experimental/CWE-369/DivideByZero.expected
@@ -1,13 +1,13 @@
edges
-| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value |
-| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:752:11:752:24 | type conversion : uint8 |
-| DivideByZero.go:752:11:752:24 | type conversion : uint8 | DivideByZero.go:753:16:753:20 | value |
+| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value |
+| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:18:11:18:24 | type conversion : uint8 |
+| DivideByZero.go:18:11:18:24 | type conversion : uint8 | DivideByZero.go:19:16:19:20 | value |
nodes
-| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
-| DivideByZero.go:745:16:745:20 | value | semmle.label | value |
-| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
-| DivideByZero.go:752:11:752:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
-| DivideByZero.go:753:16:753:20 | value | semmle.label | value |
+| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:12:16:12:20 | value | semmle.label | value |
+| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
+| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
#select
-| DivideByZero.go:745:16:745:20 | value | DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:745:16:745:20 | value | value |
-| DivideByZero.go:753:16:753:20 | value | DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:753:16:753:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:753:16:753:20 | value | value |
\ No newline at end of file
+| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:12:16:12:20 | value | value |
+| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:19:16:19:20 | value | value |
From bd09868686dffa21b97365c078620d5b3e58106f Mon Sep 17 00:00:00 2001
From: Your Name
Date: Wed, 27 Jan 2021 03:46:50 +0300
Subject: [PATCH 10/12] test fixed, comments added
Update ql/src/experimental/CWE-369/DivideByZero.qhelp
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.qhelp
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.qhelp
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
---
.../experimental/CWE-369/DivideByZero.qhelp | 11 ++++-----
ql/src/experimental/CWE-369/DivideByZero.ql | 23 ++++++++++---------
.../CWE-369/DivideByZero.expected | 4 ++--
3 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp
index c2b4d546866..2fadf452e48 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.qhelp
+++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp
@@ -3,20 +3,19 @@
Divide by zero is division where the divisor (denominator) is zero.
- In Golang language, integer divide by zero leads to panic(), which might interrupt execution of the program and lead to program termination.
+ In Go, integer divide by zero leads to a panic, which might interrupt execution of the program and lead to program termination.
- Every user input should be checked for correctness, if needed.
- In case of divide by zero, comparison with zero should be added. It is also possible to handle panic(),
- generated by division by zero, by built-in function recover().
+ Check that all user inputs used as a divisor are non-zero. It is also possible to handle a panic,
+ generated by division by zero, using the built-in function recover.
-The following example shows simplified case, when data received from user input, which is used as a divisor and
-causes divide by zero with panic signal.
+The following example shows data received from user input being used as a divisor and
+possibly causing a divide-by-zero panic.
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 4fde3b6164b..70f0b0f38c6 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -14,8 +14,11 @@ import go
import DataFlow::PathGraph
import semmle.go.dataflow.internal.TaintTrackingUtil
+/**
+ * A barrier-guard, which represents comparison and equality with zero.
+ */
class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard {
- DivideByZeroSanitizeGuard() {
+ DivideByZeroSanitizerGuard() {
this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or
this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0
}
@@ -33,6 +36,9 @@ class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard {
}
}
+/**
+ * A taint-tracking configuration for reasoning about division by zero, where divisor is user-controlled and unchecked.
+ */
class DivideByZeroCheckConfig extends TaintTracking::Configuration {
DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" }
@@ -41,27 +47,22 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Function f |
f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and
- node1 = f.getACall().getArgument(0) and
- node2 = f.getACall().getResult(0)
- )
- or
- exists(ConversionExpr ce | ce.getType().getUnderlyingType() instanceof IntegerType |
- node1.asExpr() = ce.getOperand() and
- node2.asExpr() = ce.getAChildExpr()
+ pred = f.getACall().getArgument(0) and
+ succ = f.getACall().getResult(0)
)
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
- guard instanceof DivideByZeroSanitizeGuard
+ guard instanceof DivideByZeroSanitizerGuard
}
override predicate isSink(DataFlow::Node sink) {
- exists(QuoExpr e | sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand())
+ sink = DataFlow::exprNode(any(QuoExpr e).getRightOperand())
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg
where cfg.hasFlowPath(source, sink)
select sink, source, sink,
- "Variable $@, which is used at division statement might be zero leading to a division-by-zero panic.",
+ "Variable $@ might be zero leading to a division-by-zero panic.",
sink, sink.getNode().toString()
diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected
index 0d22d93159d..f62d9ed3ef4 100644
--- a/ql/test/experimental/CWE-369/DivideByZero.expected
+++ b/ql/test/experimental/CWE-369/DivideByZero.expected
@@ -9,5 +9,5 @@ nodes
| DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
#select
-| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:12:16:12:20 | value | value |
-| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:19:16:19:20 | value | value |
+| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value |
+| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value |
From 4b24e5641ea78c4e16f93bd76932a030b7bf926d Mon Sep 17 00:00:00 2001
From: Your Name
Date: Wed, 27 Jan 2021 22:33:33 +0300
Subject: [PATCH 11/12] formatting + example
fix
test fix
Update ql/src/experimental/CWE-369/DivideByZero.ql
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.qhelp
Co-authored-by: Chris Smowton
Update ql/src/experimental/CWE-369/DivideByZero.qhelp
Co-authored-by: Chris Smowton
---
.../experimental/CWE-369/DivideByZero.qhelp | 7 ++++--
ql/src/experimental/CWE-369/DivideByZero.ql | 9 +++-----
.../experimental/CWE-369/DivideByZeroGood.go | 23 +++++++++++++++++++
.../CWE-369/DivideByZero.expected | 4 ++--
4 files changed, 33 insertions(+), 10 deletions(-)
create mode 100644 ql/src/experimental/CWE-369/DivideByZeroGood.go
diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp
index 2fadf452e48..ae39d1df890 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.qhelp
+++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp
@@ -2,8 +2,7 @@
- Divide by zero is division where the divisor (denominator) is zero.
- In Go, integer divide by zero leads to a panic, which might interrupt execution of the program and lead to program termination.
+ In Go, dividing an integer by zero leads to a panic, which might interrupt execution of the program and lead to program termination.
@@ -18,5 +17,9 @@ The following example shows data received from user input being used as a diviso
possibly causing a divide-by-zero panic.
+
+This can be fixed by testing the divisor against against zero:
+
+
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 70f0b0f38c6..8f7b0bf205d 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -1,8 +1,6 @@
/**
* @name Divide by zero
- * @description Converting the result of `strconv.Atoi`, `strconv.ParseInt`,
- * and `strconv.ParseUint` to integer types or use of integer types for division without checks
- * might lead to division by zero and panic, which cause denial of service.
+ * @description Dividing an integer by a user-controlled value may lead to division by zero and an unexpected panic.
* @kind path-problem
* @problem.severity error
* @id go/divide-by-zero
@@ -63,6 +61,5 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg
where cfg.hasFlowPath(source, sink)
-select sink, source, sink,
- "Variable $@ might be zero leading to a division-by-zero panic.",
- sink, sink.getNode().toString()
+select sink, source, sink, "Variable $@ might be zero leading to a division-by-zero panic.", sink,
+ sink.getNode().toString()
diff --git a/ql/src/experimental/CWE-369/DivideByZeroGood.go b/ql/src/experimental/CWE-369/DivideByZeroGood.go
new file mode 100644
index 00000000000..3b80421322b
--- /dev/null
+++ b/ql/src/experimental/CWE-369/DivideByZeroGood.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+func main() {
+ if len(os.Args) < 2 {
+ fmt.Printf("Usage: ./program value\n")
+ return
+ }
+ val1 := 1337
+ value, _ := strconv.Atoi(os.Args[1])
+ if value == 0 {
+ fmt.Println("Division by zero attempted!")
+ return
+ }
+ out := val1 / value
+ fmt.Println(out)
+ return
+}
diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected
index f62d9ed3ef4..215db52ab8c 100644
--- a/ql/test/experimental/CWE-369/DivideByZero.expected
+++ b/ql/test/experimental/CWE-369/DivideByZero.expected
@@ -9,5 +9,5 @@ nodes
| DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
#select
-| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value |
-| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value |
+| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value |
+| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value |
From c29ab8958f85381fabc4750c2999741bdb0fb444 Mon Sep 17 00:00:00 2001
From: user
Date: Wed, 10 Feb 2021 00:04:52 +0300
Subject: [PATCH 12/12] tests and docs updated
---
ql/src/experimental/CWE-369/DivideByZero.ql | 6 +-
.../CWE-369/DivideByZero.expected | 18 ++++++
ql/test/experimental/CWE-369/DivideByZero.go | 59 +++++++++++++++++++
3 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql
index 8f7b0bf205d..5b4518b1c6e 100644
--- a/ql/src/experimental/CWE-369/DivideByZero.ql
+++ b/ql/src/experimental/CWE-369/DivideByZero.ql
@@ -43,10 +43,10 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
- exists(Function f |
+ exists(Function f, DataFlow::CallNode cn | cn = f.getACall() |
f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and
- pred = f.getACall().getArgument(0) and
- succ = f.getACall().getResult(0)
+ pred = cn.getArgument(0) and
+ succ = cn.getResult(0)
)
}
diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected
index 215db52ab8c..370d5d099c4 100644
--- a/ql/test/experimental/CWE-369/DivideByZero.expected
+++ b/ql/test/experimental/CWE-369/DivideByZero.expected
@@ -2,12 +2,30 @@ edges
| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value |
| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:18:11:18:24 | type conversion : uint8 |
| DivideByZero.go:18:11:18:24 | type conversion : uint8 | DivideByZero.go:19:16:19:20 | value |
+| DivideByZero.go:24:12:24:16 | selection of URL : pointer type | DivideByZero.go:26:16:26:20 | value |
+| DivideByZero.go:31:12:31:16 | selection of URL : pointer type | DivideByZero.go:33:16:33:20 | value |
+| DivideByZero.go:38:12:38:16 | selection of URL : pointer type | DivideByZero.go:40:16:40:20 | value |
+| DivideByZero.go:54:12:54:16 | selection of URL : pointer type | DivideByZero.go:55:11:55:24 | type conversion : uint8 |
+| DivideByZero.go:55:11:55:24 | type conversion : uint8 | DivideByZero.go:57:17:57:21 | value |
nodes
| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
| DivideByZero.go:12:16:12:20 | value | semmle.label | value |
| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
| DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
+| DivideByZero.go:24:12:24:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:26:16:26:20 | value | semmle.label | value |
+| DivideByZero.go:31:12:31:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:33:16:33:20 | value | semmle.label | value |
+| DivideByZero.go:38:12:38:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:40:16:40:20 | value | semmle.label | value |
+| DivideByZero.go:54:12:54:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
+| DivideByZero.go:55:11:55:24 | type conversion : uint8 | semmle.label | type conversion : uint8 |
+| DivideByZero.go:57:17:57:21 | value | semmle.label | value |
#select
| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value |
| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value |
+| DivideByZero.go:26:16:26:20 | value | DivideByZero.go:24:12:24:16 | selection of URL : pointer type | DivideByZero.go:26:16:26:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:26:16:26:20 | value | value |
+| DivideByZero.go:33:16:33:20 | value | DivideByZero.go:31:12:31:16 | selection of URL : pointer type | DivideByZero.go:33:16:33:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:33:16:33:20 | value | value |
+| DivideByZero.go:40:16:40:20 | value | DivideByZero.go:38:12:38:16 | selection of URL : pointer type | DivideByZero.go:40:16:40:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:40:16:40:20 | value | value |
+| DivideByZero.go:57:17:57:21 | value | DivideByZero.go:54:12:54:16 | selection of URL : pointer type | DivideByZero.go:57:17:57:21 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:57:17:57:21 | value | value |
diff --git a/ql/test/experimental/CWE-369/DivideByZero.go b/ql/test/experimental/CWE-369/DivideByZero.go
index 575d23504f3..613479981b1 100644
--- a/ql/test/experimental/CWE-369/DivideByZero.go
+++ b/ql/test/experimental/CWE-369/DivideByZero.go
@@ -19,3 +19,62 @@ func myHandler2(w http.ResponseWriter, r *http.Request) {
out := 1337 / value
fmt.Println(out)
}
+
+func myHandler3(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.ParseInt(param1, 10, 64)
+ out := 1337 / value
+ fmt.Println(out)
+}
+
+func myHandler4(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.ParseFloat(param1, 32)
+ out := 1337 / value
+ fmt.Println(out)
+}
+
+func myHandler5(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.ParseUint(param1, 10, 64)
+ out := 1337 / value
+ fmt.Println(out)
+}
+
+func myHandler6(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value := int(param1[0])
+ if value != 0 {
+ out := 1337 / value
+ fmt.Println(out)
+ }
+}
+
+func myHandler7(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value := int(param1[0])
+ if value >= 0 {
+ out := 1337 / value
+ fmt.Println(out)
+ }
+}
+
+func myHandler8(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.ParseInt(param1, 10, 64)
+ if value > 0 {
+ out := 1337 / value
+ fmt.Println(out)
+ }
+}
+
+func myHandler9(w http.ResponseWriter, r *http.Request) {
+ param1 := r.URL.Query()["param1"][0]
+ value, _ := strconv.ParseInt(param1, 10, 64)
+ if value == 0 {
+ fmt.Println(param1)
+ return
+ }
+ out := 1337 / value
+ fmt.Println(out)
+}