-Golang's tls.Config struct accepts MinVersion parameter that sets minimum accepted TLS version.
-If the parameter is not provided, default value is used: TLS1.2 for clients, and TLS1.0 for servers.
-TLS1.0 is considered deprecated and should not be used.
+Golang's tls.Config struct accepts a MinVersion parameter that sets the minimum accepted TLS version.
+If the parameter is not provided, the default depends on the Go version in use. Since Go 1.18, crypto/tls clients default to TLS 1.2 (previously TLS 1.0).
+Since Go 1.22, crypto/tls servers also default to TLS 1.2 (previously TLS 1.0).
+
+
+This query flags tls.Config values where MinVersion is never set explicitly and the project's
+go.mod declares support for a Go version where the defaults are insecure:
+
+
+- Go < 1.18 for client-side configs (when client default is TLS 1.0)
+- Go < 1.22 for server-side configs (when server default is TLS 1.0)
+
+
+TLS 1.0 and 1.1 are deprecated and should not be used.
-Explicitly set tls version to an up-to-date one.
+Explicitly set the TLS version to TLS 1.2 or higher:
+
+- For projects using Go < 1.18: Set
MinVersion for both clients and servers
+- For projects using Go 1.18-1.21: Set
MinVersion for servers
+- For projects using Go >= 1.22: Defaults are secure, but explicit setting is still recommended
+
In this example, the http.Server may be set with TLS configuration created by either test1 or test2 functions.
-The test1 result will be highlighted by this query, as it fails to explicitly set minimum supported TLS version.
-The test2 result will not be marked, even that it also uses the default value for minimum version.
-That is because the test2 is explicit, and this query assumes that developers knew what they are doing.
+For projects with a go directive < 1.22, the test1 result will be highlighted by this query, as it fails to explicitly set minimum supported TLS version.
+The test2 result will not be marked, even though it also uses the default value for minimum version.
+That is because the test2 is explicit, and this query assumes that developers knew what they are doing.
+Note: The query behavior depends on the go directive in go.mod:
+
+- Go < 1.18: Both client and server configs without MinVersion are flagged
+- Go 1.18-1.21: Only server configs without MinVersion are flagged
+- Go >= 1.22: No configs are flagged (both defaults are secure)
+
tls.Config specification
+
+ Go 1.18 Release Notes - TLS 1.0 and 1.1 disabled by default client-side
+
+
+ Go 1.22 Release Notes - TLS 1.2 default for servers
+
\ No newline at end of file
diff --git a/go/src/security/MissingMinVersionTLS/MissingMinVersionTLS.ql b/go/src/security/MissingMinVersionTLS/MissingMinVersionTLS.ql
index b79bb8b..baa0f8d 100644
--- a/go/src/security/MissingMinVersionTLS/MissingMinVersionTLS.ql
+++ b/go/src/security/MissingMinVersionTLS/MissingMinVersionTLS.ql
@@ -1,7 +1,7 @@
/**
* @name Missing MinVersion in tls.Config
* @id tob/go/missing-min-version-tls
- * @description This rule finds cases when you do not set the `tls.Config.MinVersion` explicitly for servers. By default version 1.0 is used, which is considered insecure. This rule does not mark explicitly set insecure versions
+ * @description Finds uses of tls.Config where MinVersion is not set and the project's minimum Go version (from go.mod) indicates insecure defaults: Go < 1.18 for clients or Go < 1.22 for servers. Does not mark explicitly set versions (including explicitly insecure ones).
* @kind problem
* @tags security
* @problem.severity error
@@ -11,6 +11,7 @@
*/
import go
+import semmle.go.GoMod as GoMod
/**
* Flow of a `tls.Config` to a write to the `MinVersion` field.
@@ -19,67 +20,59 @@ module TlsVersionConfig implements DataFlow::ConfigSig {
/**
* Holds if `source` is a TLS.Config instance.
*/
- predicate isSource(DataFlow::Node source) {
- exists(Variable v |
- configOrConfigPointer(v.getType()) and
- source.asExpr() = v.getAReference()
- )
- }
-
+ predicate isSource(DataFlow::Node source) {
+ exists(Variable v |
+ configOrConfigPointer(v.getType()) and
+ source.asExpr() = v.getAReference()
+ )
+ }
+
/**
* Holds if a write to `sink`.MinVersion exists.
*/
- predicate isSink(DataFlow::Node sink) {
- exists(Write fieldWrite, Field fld |
- fld.hasQualifiedName( "crypto/tls", "Config", "MinVersion") and
- fieldWrite.writesField(sink, fld, _)
- )
- }
+ predicate isSink(DataFlow::Node sink) {
+ exists(Write fieldWrite, Field fld |
+ fld.hasQualifiedName("crypto/tls", "Config", "MinVersion") and
+ fieldWrite.writesField(sink, fld, _)
+ )
+ }
}
module TlsVersionFlow = TaintTracking::Global