From 766eaabdec151158dd7c70366dd9f1bc5cc1af63 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Wed, 9 Jul 2025 14:55:27 +0100
Subject: [PATCH 01/18] Move weak crypto algorithm query out of experimental
---
go/ql/src/{experimental => Security}/CWE-327/CryptoLibraries.qll | 0
.../{experimental => Security}/CWE-327/WeakCryptoAlgorithm.qhelp | 0
.../src/{experimental => Security}/CWE-327/WeakCryptoAlgorithm.ql | 0
.../CWE-327/WeakCryptoAlgorithmCustomizations.qll | 0
go/ql/src/{experimental => Security}/CWE-327/examples/Crypto.go | 0
.../CWE-327/examples/InsecureRandomness.go | 0
6 files changed, 0 insertions(+), 0 deletions(-)
rename go/ql/src/{experimental => Security}/CWE-327/CryptoLibraries.qll (100%)
rename go/ql/src/{experimental => Security}/CWE-327/WeakCryptoAlgorithm.qhelp (100%)
rename go/ql/src/{experimental => Security}/CWE-327/WeakCryptoAlgorithm.ql (100%)
rename go/ql/src/{experimental => Security}/CWE-327/WeakCryptoAlgorithmCustomizations.qll (100%)
rename go/ql/src/{experimental => Security}/CWE-327/examples/Crypto.go (100%)
rename go/ql/src/{experimental => Security}/CWE-327/examples/InsecureRandomness.go (100%)
diff --git a/go/ql/src/experimental/CWE-327/CryptoLibraries.qll b/go/ql/src/Security/CWE-327/CryptoLibraries.qll
similarity index 100%
rename from go/ql/src/experimental/CWE-327/CryptoLibraries.qll
rename to go/ql/src/Security/CWE-327/CryptoLibraries.qll
diff --git a/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithm.qhelp b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.qhelp
similarity index 100%
rename from go/ql/src/experimental/CWE-327/WeakCryptoAlgorithm.qhelp
rename to go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.qhelp
diff --git a/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
similarity index 100%
rename from go/ql/src/experimental/CWE-327/WeakCryptoAlgorithm.ql
rename to go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
diff --git a/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithmCustomizations.qll
similarity index 100%
rename from go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll
rename to go/ql/src/Security/CWE-327/WeakCryptoAlgorithmCustomizations.qll
diff --git a/go/ql/src/experimental/CWE-327/examples/Crypto.go b/go/ql/src/Security/CWE-327/examples/Crypto.go
similarity index 100%
rename from go/ql/src/experimental/CWE-327/examples/Crypto.go
rename to go/ql/src/Security/CWE-327/examples/Crypto.go
diff --git a/go/ql/src/experimental/CWE-327/examples/InsecureRandomness.go b/go/ql/src/Security/CWE-327/examples/InsecureRandomness.go
similarity index 100%
rename from go/ql/src/experimental/CWE-327/examples/InsecureRandomness.go
rename to go/ql/src/Security/CWE-327/examples/InsecureRandomness.go
From f1af8b8f5a770d28d2945dc8326e203723b7d164 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 18 Jul 2025 22:28:40 +0100
Subject: [PATCH 02/18] Convert test to inline expectations
---
.../query-tests/Security/CWE-327/Crypto.go | 12 ++++----
.../CWE-327/WeakCryptoAlgorithm.expected | 28 +++++++++----------
.../CWE-327/WeakCryptoAlgorithm.qlref | 5 +++-
3 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/go/ql/test/query-tests/Security/CWE-327/Crypto.go b/go/ql/test/query-tests/Security/CWE-327/Crypto.go
index 75229b020a86..a58052df38d7 100644
--- a/go/ql/test/query-tests/Security/CWE-327/Crypto.go
+++ b/go/ql/test/query-tests/Security/CWE-327/Crypto.go
@@ -13,19 +13,21 @@ func crypto() {
public := []byte("hello")
password := []byte("123456")
- buf := password // testing dataflow by passing into different variable
+
+ // testing dataflow by passing into different variable
+ buf := password // $ Source
// BAD, des is a weak crypto algorithm and password is sensitive data
- des.NewTripleDESCipher(buf)
+ des.NewTripleDESCipher(buf) // $ Alert
// BAD, md5 is a weak crypto algorithm and password is sensitive data
- md5.Sum(buf)
+ md5.Sum(buf) // $ Alert
// BAD, rc4 is a weak crypto algorithm and password is sensitive data
- rc4.NewCipher(buf)
+ rc4.NewCipher(buf) // $ Alert
// BAD, sha1 is a weak crypto algorithm and password is sensitive data
- sha1.Sum(buf)
+ sha1.Sum(buf) // $ Alert
// GOOD, password is sensitive data but aes is a strong crypto algorithm
aes.NewCipher(buf)
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected b/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected
index 53cfd40145d3..6f40dfcc7ad0 100644
--- a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected
+++ b/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected
@@ -1,17 +1,17 @@
+#select
+| Crypto.go:21:25:21:27 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:21:25:21:27 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
+| Crypto.go:24:10:24:12 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:24:10:24:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
+| Crypto.go:27:16:27:18 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:27:16:27:18 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
+| Crypto.go:30:11:30:13 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:30:11:30:13 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
edges
-| Crypto.go:16:9:16:16 | password | Crypto.go:19:25:19:27 | buf | provenance | |
-| Crypto.go:16:9:16:16 | password | Crypto.go:22:10:22:12 | buf | provenance | |
-| Crypto.go:16:9:16:16 | password | Crypto.go:25:16:25:18 | buf | provenance | |
-| Crypto.go:16:9:16:16 | password | Crypto.go:28:11:28:13 | buf | provenance | |
+| Crypto.go:18:9:18:16 | password | Crypto.go:21:25:21:27 | buf | provenance | |
+| Crypto.go:18:9:18:16 | password | Crypto.go:24:10:24:12 | buf | provenance | |
+| Crypto.go:18:9:18:16 | password | Crypto.go:27:16:27:18 | buf | provenance | |
+| Crypto.go:18:9:18:16 | password | Crypto.go:30:11:30:13 | buf | provenance | |
nodes
-| Crypto.go:16:9:16:16 | password | semmle.label | password |
-| Crypto.go:19:25:19:27 | buf | semmle.label | buf |
-| Crypto.go:22:10:22:12 | buf | semmle.label | buf |
-| Crypto.go:25:16:25:18 | buf | semmle.label | buf |
-| Crypto.go:28:11:28:13 | buf | semmle.label | buf |
+| Crypto.go:18:9:18:16 | password | semmle.label | password |
+| Crypto.go:21:25:21:27 | buf | semmle.label | buf |
+| Crypto.go:24:10:24:12 | buf | semmle.label | buf |
+| Crypto.go:27:16:27:18 | buf | semmle.label | buf |
+| Crypto.go:30:11:30:13 | buf | semmle.label | buf |
subpaths
-#select
-| Crypto.go:19:25:19:27 | buf | Crypto.go:16:9:16:16 | password | Crypto.go:19:25:19:27 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:16:9:16:16 | password | Sensitive data |
-| Crypto.go:22:10:22:12 | buf | Crypto.go:16:9:16:16 | password | Crypto.go:22:10:22:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:16:9:16:16 | password | Sensitive data |
-| Crypto.go:25:16:25:18 | buf | Crypto.go:16:9:16:16 | password | Crypto.go:25:16:25:18 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:16:9:16:16 | password | Sensitive data |
-| Crypto.go:28:11:28:13 | buf | Crypto.go:16:9:16:16 | password | Crypto.go:28:11:28:13 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:16:9:16:16 | password | Sensitive data |
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref b/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref
index 00d68df5a7c5..cdc89fa3080b 100644
--- a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref
+++ b/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref
@@ -1 +1,4 @@
-experimental/CWE-327/WeakCryptoAlgorithm.ql
+query: Security/CWE-327/WeakCryptoAlgorithm.ql
+postprocess:
+ - utils/test/PrettyPrintModels.ql
+ - utils/test/InlineExpectationsTestQuery.ql
From a0ba752faa647da4dd2ce6f388e94909a9a0a5dc Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Wed, 9 Jul 2025 14:55:54 +0100
Subject: [PATCH 03/18] Remove `experimental` tag from query metadata
---
go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql | 1 -
1 file changed, 1 deletion(-)
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
index ffaaae8e02a5..c649bc8e374e 100644
--- a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
+++ b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
@@ -5,7 +5,6 @@
* @problem.severity error
* @id go/weak-crypto-algorithm
* @tags security
- * experimental
* external/cwe/cwe-327
* external/cwe/cwe-328
*/
From 993afd26fbe0ce784cdd5abdf94629641f1687ff Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 10 Jul 2025 16:29:48 +0100
Subject: [PATCH 04/18] Align metadata with related queries
---
go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
index c649bc8e374e..3de3a8d34ce1 100644
--- a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
+++ b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
@@ -1,8 +1,10 @@
/**
- * @name Use of a weak cryptographic algorithm
- * @description Using weak cryptographic algorithms can allow an attacker to compromise security.
+ * @name Use of a broken or weak cryptographic algorithm
+ * @description Using broken or weak cryptographic algorithms can compromise security.
* @kind path-problem
- * @problem.severity error
+ * @problem.severity warning
+ * @security-severity 7.5
+ * @precision high
* @id go/weak-crypto-algorithm
* @tags security
* external/cwe/cwe-327
From dbd1bfd4172a4bcb8c07e0221e7b84075f249038 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 17 Jul 2025 14:56:38 +0100
Subject: [PATCH 05/18] Move crypto qll files from query pack to library pack
---
.../CWE-327 => lib/semmle/go/frameworks}/CryptoLibraries.qll | 0
.../semmle/go/security}/WeakCryptoAlgorithmCustomizations.qll | 2 +-
go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql | 2 +-
3 files changed, 2 insertions(+), 2 deletions(-)
rename go/ql/{src/Security/CWE-327 => lib/semmle/go/frameworks}/CryptoLibraries.qll (100%)
rename go/ql/{src/Security/CWE-327 => lib/semmle/go/security}/WeakCryptoAlgorithmCustomizations.qll (97%)
diff --git a/go/ql/src/Security/CWE-327/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
similarity index 100%
rename from go/ql/src/Security/CWE-327/CryptoLibraries.qll
rename to go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithmCustomizations.qll b/go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
similarity index 97%
rename from go/ql/src/Security/CWE-327/WeakCryptoAlgorithmCustomizations.qll
rename to go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
index b9104f1fe096..6e25789531f4 100644
--- a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithmCustomizations.qll
+++ b/go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
@@ -5,8 +5,8 @@
*/
import go
+private import semmle.go.frameworks.CryptoLibraries
private import semmle.go.security.SensitiveActions
-private import CryptoLibraries
/**
* Provides default sources, sinks and sanitizers for reasoning about
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
index 3de3a8d34ce1..58adfc003440 100644
--- a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
+++ b/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
@@ -12,7 +12,7 @@
*/
import go
-import WeakCryptoAlgorithmCustomizations
+import semmle.go.security.WeakCryptoAlgorithmCustomizations
import WeakCryptoAlgorithm::Flow::PathGraph
from WeakCryptoAlgorithm::Flow::PathNode source, WeakCryptoAlgorithm::Flow::PathNode sink
From ae3849203d78faf9da15c839c06eb9eaaad0b303 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 18 Jul 2025 16:14:45 +0100
Subject: [PATCH 06/18] Copy the structure of the Javascript query
---
go/ql/lib/go.qll | 1 +
go/ql/lib/qlpack.yml | 1 +
go/ql/lib/semmle/go/Concepts.qll | 32 ++++
.../semmle/go/frameworks/CryptoLibraries.qll | 177 ++----------------
.../BrokenCryptoAlgorithmCustomizations.qll | 58 ++++++
.../security/BrokenCryptoAlgorithmQuery.qll | 41 ++++
.../WeakCryptoAlgorithmCustomizations.qll | 66 -------
...ithm.qhelp => BrokenCryptoAlgorithm.qhelp} | 0
...oAlgorithm.ql => BrokenCryptoAlgorithm.ql} | 8 +-
...xpected => BrokenCryptoAlgorithm.expected} | 0
...ithm.qlref => BrokenCryptoAlgorithm.qlref} | 2 +-
11 files changed, 152 insertions(+), 234 deletions(-)
create mode 100644 go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
create mode 100644 go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
delete mode 100644 go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
rename go/ql/src/Security/CWE-327/{WeakCryptoAlgorithm.qhelp => BrokenCryptoAlgorithm.qhelp} (100%)
rename go/ql/src/Security/CWE-327/{WeakCryptoAlgorithm.ql => BrokenCryptoAlgorithm.ql} (66%)
rename go/ql/test/query-tests/Security/CWE-327/{WeakCryptoAlgorithm.expected => BrokenCryptoAlgorithm.expected} (100%)
rename go/ql/test/query-tests/Security/CWE-327/{WeakCryptoAlgorithm.qlref => BrokenCryptoAlgorithm.qlref} (65%)
diff --git a/go/ql/lib/go.qll b/go/ql/lib/go.qll
index 16f2f1702faa..688214aae855 100644
--- a/go/ql/lib/go.qll
+++ b/go/ql/lib/go.qll
@@ -33,6 +33,7 @@ import semmle.go.frameworks.AwsLambda
import semmle.go.frameworks.Beego
import semmle.go.frameworks.BeegoOrm
import semmle.go.frameworks.Bun
+import semmle.go.frameworks.CryptoLibraries
import semmle.go.frameworks.RsCors
import semmle.go.frameworks.Couchbase
import semmle.go.frameworks.Echo
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index bf2586d9089e..145bb4747ff6 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -6,6 +6,7 @@ extractor: go
library: true
upgrades: upgrades
dependencies:
+ codeql/concepts: ${workspace}
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/threat-models: ${workspace}
diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll
index 1931f16871ab..0f30519d0beb 100644
--- a/go/ql/lib/semmle/go/Concepts.qll
+++ b/go/ql/lib/semmle/go/Concepts.qll
@@ -8,6 +8,10 @@ import go
import semmle.go.dataflow.FunctionInputsAndOutputs
import semmle.go.concepts.HTTP
import semmle.go.concepts.GeneratedFile
+private import codeql.concepts.ConceptsShared
+private import semmle.go.dataflow.internal.DataFlowImplSpecific
+
+private module ConceptsShared = ConceptsMake;
/**
* A data-flow node that executes an operating system command,
@@ -505,3 +509,31 @@ module UnmarshalingFunction {
abstract string getFormat();
}
}
+
+/**
+ * Provides models for cryptographic things.
+ */
+module Cryptography {
+ private import ConceptsShared::Cryptography as SC
+
+ /**
+ * A data-flow node that is an application of a cryptographic algorithm. For example,
+ * encryption, decryption, signature-validation.
+ *
+ * Extend this class to refine existing API models. If you want to model new APIs,
+ * extend `CryptographicOperation::Range` instead.
+ */
+ class CryptographicOperation extends SC::CryptographicOperation { }
+
+ class EncryptionAlgorithm = SC::EncryptionAlgorithm;
+
+ class HashingAlgorithm = SC::HashingAlgorithm;
+
+ class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm;
+
+ module CryptographicOperation = SC::CryptographicOperation;
+
+ class BlockMode = SC::BlockMode;
+
+ class CryptographicAlgorithm = SC::CryptographicAlgorithm;
+}
diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
index 5518067b668b..9cc0235cbbb3 100644
--- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
+++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
@@ -3,180 +3,31 @@
*/
import go
+import semmle.go.Concepts::Cryptography
+private import codeql.concepts.internal.CryptoAlgorithmNames
/**
- * Names of cryptographic algorithms, separated into strong and weak variants.
- *
- * The names are normalized: upper-case, no spaces, dashes or underscores.
- *
- * The names are inspired by the names used in real world crypto libraries.
- *
- * The classification into strong and weak are based on OWASP and Wikipedia (2020).
- *
- * Sources (more links in qhelp file):
- * https://en.wikipedia.org/wiki/Strong_cryptography#Cryptographically_strong_algorithms
- * https://en.wikipedia.org/wiki/Strong_cryptography#Examples
- * https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
- */
-private module AlgorithmNames {
- predicate isStrongHashingAlgorithm(string name) {
- name =
- [
- "DSA", "ED25519", "SHA256", "SHA384", "SHA512", "SHA3", "ES256", "ECDSA256", "ES384",
- "ECDSA384", "ES512", "ECDSA512", "SHA2", "SHA224"
- ]
- }
-
- predicate isWeakHashingAlgorithm(string name) {
- name =
- [
- "HAVEL128", "MD2", "SHA1", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256",
- "RIPEMD320", "SHA0"
- ]
- }
-
- predicate isStrongEncryptionAlgorithm(string name) {
- name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
- }
-
- predicate isWeakEncryptionAlgorithm(string name) {
- name =
- [
- "DES", "3DES", "ARC5", "RC5", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4",
- "RC4", "ARCFOUR"
- ]
- }
-
- predicate isStrongPasswordHashingAlgorithm(string name) {
- name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
- }
-
- predicate isWeakPasswordHashingAlgorithm(string name) { none() }
-}
-
-private import AlgorithmNames
-
-/**
- * A cryptographic algorithm.
- */
-private newtype TCryptographicAlgorithm =
- MkHashingAlgorithm(string name, boolean isWeak) {
- isStrongHashingAlgorithm(name) and isWeak = false
- or
- isWeakHashingAlgorithm(name) and isWeak = true
- } or
- MkEncryptionAlgorithm(string name, boolean isWeak) {
- isStrongEncryptionAlgorithm(name) and isWeak = false
- or
- isWeakEncryptionAlgorithm(name) and isWeak = true
- } or
- MkPasswordHashingAlgorithm(string name, boolean isWeak) {
- isStrongPasswordHashingAlgorithm(name) and isWeak = false
- or
- isWeakPasswordHashingAlgorithm(name) and isWeak = true
- }
-
-/**
- * A cryptographic algorithm.
- */
-abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
- /** Gets a textual representation of this element. */
- string toString() { result = this.getName() }
-
- /**
- * Gets the name of this algorithm.
- */
- abstract string getName();
-
- /**
- * Holds if the name of this algorithm matches `name` modulo case,
- * white space, dashes and underscores.
- */
- bindingset[name]
- predicate matchesName(string name) {
- exists(name.regexpReplaceAll("[-_]", "").regexpFind("(?i)\\Q" + this.getName() + "\\E", _, _))
- }
-
- /**
- * Holds if this algorithm is weak.
- */
- abstract predicate isWeak();
-}
-
-/**
- * A hashing algorithm such as `MD5` or `SHA512`.
- */
-class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
- string name;
- boolean isWeak;
-
- HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
-
- override string getName() { result = name }
-
- override predicate isWeak() { isWeak = true }
-}
-
-/**
- * An encryption algorithm such as `DES` or `AES512`.
- */
-class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
- string name;
- boolean isWeak;
-
- EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
-
- override string getName() { result = name }
-
- override predicate isWeak() { isWeak = true }
-}
-
-/**
- * A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
- */
-class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
- string name;
- boolean isWeak;
-
- PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
-
- override string getName() { result = name }
-
- override predicate isWeak() { isWeak = true }
-}
-
-/**
- * An application of a cryptographic algorithm.
+ * A cryptographic operation from the `crypto/md5` package.
*/
-abstract class CryptographicOperation extends DataFlow::Node {
- /**
- * Gets the input the algorithm is used on, e.g. the plain text input to be encrypted.
- */
- abstract Expr getInput();
+private module CryptoMd5 {
+ private class Md5 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
+ Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
- /**
- * Gets the applied algorithm.
- */
- abstract CryptographicAlgorithm getAlgorithm();
-}
+ override DataFlow::Node getInitialization() { result = this }
-/**
- * A cryptographic operation from the `crypto/md5` package.
- */
-class Md5 extends CryptographicOperation, DataFlow::CallNode {
- Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
+ override CryptographicAlgorithm getAlgorithm() { result.matchesName("MD5") }
- override Expr getInput() { result = this.getArgument(0).asExpr() }
+ override DataFlow::Node getAnInput() { result = super.getArgument(0) }
- override CryptographicAlgorithm getAlgorithm() {
- result.matchesName(this.getTarget().getPackage().getName())
+ // not relevant for md5
+ override BlockMode getBlockMode() { none() }
}
}
/**
* A cryptographic operation from the `crypto/sha1` package.
*/
-class Sha1 extends CryptographicOperation, DataFlow::CallNode {
+class Sha1 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
Sha1() { this.getTarget().hasQualifiedName("crypto/sha1", ["New", "Sum"]) }
override Expr getInput() { result = this.getArgument(0).asExpr() }
@@ -189,7 +40,7 @@ class Sha1 extends CryptographicOperation, DataFlow::CallNode {
/**
* A cryptographic operation from the `crypto/des` package.
*/
-class Des extends CryptographicOperation, DataFlow::CallNode {
+class Des extends CryptographicOperation::Range instanceof DataFlow::CallNode {
Des() { this.getTarget().hasQualifiedName("crypto/des", ["NewCipher", "NewTripleDESCipher"]) }
override Expr getInput() { result = this.getArgument(0).asExpr() }
@@ -202,7 +53,7 @@ class Des extends CryptographicOperation, DataFlow::CallNode {
/**
* A cryptographic operation from the `crypto/rc4` package.
*/
-class Rc4 extends CryptographicOperation, DataFlow::CallNode {
+class Rc4 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
Rc4() { this.getTarget().hasQualifiedName("crypto/rc4", "NewCipher") }
override Expr getInput() { result = this.getArgument(0).asExpr() }
diff --git a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
new file mode 100644
index 000000000000..e5ac77fbb75f
--- /dev/null
+++ b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
@@ -0,0 +1,58 @@
+/**
+ * Provides default sources, sinks and sanitizers for reasoning about
+ * sensitive information in weak cryptographic algorithms,
+ * as well as extension points for adding your own.
+ */
+
+import go
+private import semmle.go.security.SensitiveActions
+
+/**
+ * Provides default sources, sinks and sanitizers for reasoning about
+ * sensitive information in weak cryptographic algorithms,
+ * as well as extension points for adding your own.
+ */
+module BrokenCryptoAlgorithm {
+ /**
+ * A data flow source for sensitive information in broken or weak cryptographic algorithms.
+ */
+ abstract class Source extends DataFlow::Node { }
+
+ /**
+ * A data flow sink for sensitive information in broken or weak cryptographic algorithms.
+ */
+ abstract class Sink extends DataFlow::Node {
+ /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
+ abstract DataFlow::Node getInitialization();
+ }
+
+ /**
+ * A sanitizer for sensitive information in broken or weak cryptographic algorithms.
+ */
+ abstract class Sanitizer extends DataFlow::Node { }
+
+ /**
+ * A sensitive source.
+ */
+ class SensitiveSource extends Source {
+ SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
+ }
+
+ /**
+ * An expression used by a broken or weak cryptographic algorithm.
+ */
+ class WeakCryptographicOperationSink extends Sink {
+ CryptographicOperation application;
+
+ WeakCryptographicOperationSink() {
+ (
+ application.getAlgorithm().isWeak()
+ or
+ application.getBlockMode().isWeak()
+ ) and
+ this = application.getAnInput()
+ }
+
+ override DataFlow::Node getInitialization() { result = application.getInitialization() }
+ }
+}
diff --git a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
new file mode 100644
index 000000000000..2e400c76c85a
--- /dev/null
+++ b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
@@ -0,0 +1,41 @@
+/**
+ * Provides a taint tracking configuration for reasoning about
+ * sensitive information in broken or weak cryptographic algorithms.
+ *
+ * Note, for performance reasons: only import this file if
+ * `BrokenCryptoAlgorithm::Configuration` is needed, otherwise
+ * `BrokenCryptoAlgorithmCustomizations` should be imported instead.
+ */
+
+import go
+import BrokenCryptoAlgorithmCustomizations::BrokenCryptoAlgorithm
+
+/**
+ * A taint tracking configuration for sensitive information in broken or weak cryptographic algorithms.
+ *
+ * This configuration identifies flows from `Source`s, which are sources of
+ * sensitive data, to `Sink`s, which is an abstract class representing all
+ * the places sensitive data may used in broken or weak cryptographic algorithms. Additional sources or sinks can be
+ * added either by extending the relevant class, or by subclassing this configuration itself,
+ * and amending the sources and sinks.
+ */
+private module BrokenCryptoAlgorithmConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
+
+ predicate observeDiffInformedIncrementalMode() { any() }
+
+ Location getASelectedSinkLocation(DataFlow::Node sink) {
+ result = sink.(Sink).getLocation()
+ or
+ result = sink.(Sink).getInitialization().getLocation()
+ }
+}
+
+/**
+ * Taint tracking flow for sensitive information in broken or weak cryptographic algorithms.
+ */
+module BrokenCryptoAlgorithmFlow = TaintTracking::Global;
diff --git a/go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll b/go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
deleted file mode 100644
index 6e25789531f4..000000000000
--- a/go/ql/lib/semmle/go/security/WeakCryptoAlgorithmCustomizations.qll
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Provides default sources, sinks and sanitizers for reasoning about
- * sensitive information in weak cryptographic algorithms,
- * as well as extension points for adding your own.
- */
-
-import go
-private import semmle.go.frameworks.CryptoLibraries
-private import semmle.go.security.SensitiveActions
-
-/**
- * Provides default sources, sinks and sanitizers for reasoning about
- * sensitive information in weak cryptographic algorithms,
- * as well as extension points for adding your own.
- */
-module WeakCryptoAlgorithm {
- /**
- * A data flow source for sensitive information in weak cryptographic algorithms.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for sensitive information in weak cryptographic algorithms.
- */
- abstract class Sink extends DataFlow::Node { }
-
- /**
- * A sanitizer for sensitive information in weak cryptographic algorithms.
- */
- abstract class Sanitizer extends DataFlow::Node { }
-
- /**
- * A sensitive source.
- */
- class SensitiveSource extends Source {
- SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
- }
-
- /**
- * An expression used by a weak cryptographic algorithm.
- */
- class WeakCryptographicOperationSink extends Sink {
- WeakCryptographicOperationSink() {
- exists(CryptographicOperation application |
- application.getAlgorithm().isWeak() and
- this.asExpr() = application.getInput()
- )
- }
- }
-
- private module Config implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
-
- predicate observeDiffInformedIncrementalMode() { any() }
- }
-
- /**
- * Tracks taint flow from sensitive information to weak cryptographic
- * algorithms.
- */
- module Flow = TaintTracking::Global;
-}
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.qhelp b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp
similarity index 100%
rename from go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.qhelp
rename to go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp
diff --git a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
similarity index 66%
rename from go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
rename to go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
index 58adfc003440..714a1cc7b3ec 100644
--- a/go/ql/src/Security/CWE-327/WeakCryptoAlgorithm.ql
+++ b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
@@ -12,10 +12,10 @@
*/
import go
-import semmle.go.security.WeakCryptoAlgorithmCustomizations
-import WeakCryptoAlgorithm::Flow::PathGraph
+import semmle.go.security.BrokenCryptoAlgorithmQuery
+import BrokenCryptoAlgorithmFlow::PathGraph
-from WeakCryptoAlgorithm::Flow::PathNode source, WeakCryptoAlgorithm::Flow::PathNode sink
-where WeakCryptoAlgorithm::Flow::flowPath(source, sink)
+from BrokenCryptoAlgorithmFlow::PathNode source, BrokenCryptoAlgorithmFlow::PathNode sink
+where BrokenCryptoAlgorithmFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "$@ is used in a weak cryptographic algorithm.",
source.getNode(), "Sensitive data"
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
similarity index 100%
rename from go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.expected
rename to go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref
similarity index 65%
rename from go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref
rename to go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref
index cdc89fa3080b..a618df1ed20a 100644
--- a/go/ql/test/query-tests/Security/CWE-327/WeakCryptoAlgorithm.qlref
+++ b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref
@@ -1,4 +1,4 @@
-query: Security/CWE-327/WeakCryptoAlgorithm.ql
+query: Security/CWE-327/BrokenCryptoAlgorithm.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql
From f0e7681ce0292e2d5212143d47d30048044d5878 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 14 Oct 2025 13:52:20 +0100
Subject: [PATCH 07/18] Avoid duplicate results using in-barriers
---
go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll | 2 ++
1 file changed, 2 insertions(+)
diff --git a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
index 2e400c76c85a..ba24dcf57078 100644
--- a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
+++ b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
@@ -24,6 +24,8 @@ private module BrokenCryptoAlgorithmConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+ predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate observeDiffInformedIncrementalMode() { any() }
From 6e6c47608437eb9f0e73d30f0293de2a0922a461 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Wed, 15 Oct 2025 12:10:22 +0100
Subject: [PATCH 08/18] Model cryptographic operations
---
go/ql/lib/semmle/go/Concepts.qll | 67 +++
.../semmle/go/frameworks/CryptoLibraries.qll | 480 +++++++++++++++++-
.../CWE-327/BrokenCryptoAlgorithm.expected | 92 +++-
.../query-tests/Security/CWE-327/Crypto.go | 255 +++++++++-
.../Security/CWE-327/CryptoAlgorithm.expected | 2 +
.../Security/CWE-327/CryptoAlgorithm.ql | 47 ++
.../test/query-tests/Security/CWE-327/go.mod | 3 +
.../internal/CryptoAlgorithmNames.qll | 3 +-
8 files changed, 879 insertions(+), 70 deletions(-)
create mode 100644 go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.expected
create mode 100644 go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.ql
create mode 100644 go/ql/test/query-tests/Security/CWE-327/go.mod
diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll
index 0f30519d0beb..acb16b62d077 100644
--- a/go/ql/lib/semmle/go/Concepts.qll
+++ b/go/ql/lib/semmle/go/Concepts.qll
@@ -536,4 +536,71 @@ module Cryptography {
class BlockMode = SC::BlockMode;
class CryptographicAlgorithm = SC::CryptographicAlgorithm;
+
+ /** A data flow node that initializes a hash algorithm. */
+ abstract class HashAlgorithmInit extends DataFlow::Node {
+ /** Gets the hash algorithm being initialized. */
+ abstract HashingAlgorithm getAlgorithm();
+ }
+
+ /** A data flow node that is an application of a hash algorithm. */
+ abstract class HashOperation extends CryptographicOperation::Range {
+ override BlockMode getBlockMode() { none() }
+ }
+
+ /** A data flow node that initializes an encryption algorithm. */
+ abstract class EncryptionAlgorithmInit extends DataFlow::Node {
+ /** Gets the encryption algorithm being initialized. */
+ abstract EncryptionAlgorithm getAlgorithm();
+ }
+
+ /**
+ * A data flow node that initializes a block cipher mode of operation, and
+ * may also propagate taint for encryption algorithms.
+ */
+ abstract class BlockModeInit extends DataFlow::CallNode {
+ /** Gets the block cipher mode of operation being initialized. */
+ abstract BlockMode getMode();
+
+ /** Gets a step propagating the encryption algorithm through this call. */
+ abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
+ }
+
+ /**
+ * A data flow node that is an application of an encryption algorithm, where
+ * the encryption algorithm and the block cipher mode of operation (if there
+ * is one) have been initialized separately.
+ */
+ abstract class EncryptionOperation extends CryptographicOperation::Range {
+ DataFlow::Node encryptionFlowTarget;
+ DataFlow::Node inputNode;
+
+ override DataFlow::Node getInitialization() {
+ EncryptionFlow::flow(result, encryptionFlowTarget)
+ }
+
+ override EncryptionAlgorithm getAlgorithm() {
+ result = this.getInitialization().(EncryptionAlgorithmInit).getAlgorithm()
+ }
+
+ override DataFlow::Node getAnInput() { result = inputNode }
+
+ override BlockMode getBlockMode() {
+ result = this.getInitialization().(BlockModeInit).getMode()
+ }
+ }
+
+ /**
+ * An `EncryptionOperation` which is a method call where the encryption
+ * algorithm and block cipher mode of operation (if there is one) flow to the
+ * receiver and the input is an argument.
+ */
+ abstract class EncryptionMethodCall extends EncryptionOperation instanceof DataFlow::CallNode {
+ int inputArg;
+
+ EncryptionMethodCall() {
+ encryptionFlowTarget = super.getReceiver() and
+ inputNode = super.getArgument(inputArg)
+ }
+ }
}
diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
index 9cc0235cbbb3..0c56d8c7e6a5 100644
--- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
+++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
@@ -7,58 +7,482 @@ import semmle.go.Concepts::Cryptography
private import codeql.concepts.internal.CryptoAlgorithmNames
/**
- * A cryptographic operation from the `crypto/md5` package.
+ * A data flow call node that is an application of a hash operation where the
+ * hash algorithm is defined in any earlier initialization node, and the input
+ * is the first argument of the call.
*/
-private module CryptoMd5 {
- private class Md5 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
- Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
+abstract class DirectHashOperation extends HashOperation instanceof DataFlow::CallNode {
+ override DataFlow::Node getInitialization() { result = this }
- override DataFlow::Node getInitialization() { result = this }
+ override DataFlow::Node getAnInput() { result = super.getArgument(0) }
+}
- override CryptographicAlgorithm getAlgorithm() { result.matchesName("MD5") }
+private module HashConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof HashAlgorithmInit }
- override DataFlow::Node getAnInput() { result = super.getArgument(0) }
+ predicate isSink(DataFlow::Node sink) { any() }
- // not relevant for md5
- override BlockMode getBlockMode() { none() }
- }
+ predicate observeDiffInformedIncrementalMode() { any() }
}
+/** Tracks the flow of hash algorithms. */
+module HashFlow = DataFlow::Global;
+
/**
- * A cryptographic operation from the `crypto/sha1` package.
+ * A data flow node that initializes a block mode and propagates the encryption
+ * algorithm from the first argument to the receiver.
*/
-class Sha1 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
- Sha1() { this.getTarget().hasQualifiedName("crypto/sha1", ["New", "Sum"]) }
+abstract class StdLibNewEncrypter extends BlockModeInit {
+ override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
+ node1 = this.getArgument(0) and
+ node2 = this.getResult(0)
+ }
+}
+
+private module EncryptionConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source instanceof EncryptionAlgorithmInit or
+ source instanceof BlockModeInit
+ }
- override Expr getInput() { result = this.getArgument(0).asExpr() }
+ predicate isSink(DataFlow::Node sink) { any() }
- override CryptographicAlgorithm getAlgorithm() {
- result.matchesName(this.getTarget().getPackage().getName())
+ predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ any(BlockModeInit nbcm).step(node1, node2)
}
+
+ predicate observeDiffInformedIncrementalMode() { any() }
}
/**
- * A cryptographic operation from the `crypto/des` package.
+ * Tracks algorithms and block cipher modes of operation used for encryption.
*/
-class Des extends CryptographicOperation::Range instanceof DataFlow::CallNode {
- Des() { this.getTarget().hasQualifiedName("crypto/des", ["NewCipher", "NewTripleDESCipher"]) }
+module EncryptionFlow = DataFlow::Global;
+
+private module Crypto {
+ private module Aes {
+ private class NewCipher extends EncryptionAlgorithmInit {
+ NewCipher() {
+ exists(Function f | this = f.getACall().getResult(0) |
+ f.hasQualifiedName("crypto/aes", "NewCipher")
+ )
+ }
+
+ override EncryptionAlgorithm getAlgorithm() { result.matchesName("AES") }
+ }
+ }
+
+ private module Des {
+ private class NewCipher extends EncryptionAlgorithmInit {
+ NewCipher() {
+ exists(Function f | this = f.getACall().getResult(0) |
+ f.hasQualifiedName("crypto/des", "NewCipher")
+ )
+ }
+
+ override EncryptionAlgorithm getAlgorithm() { result.matchesName("DES") }
+ }
+
+ private class NewTripleDESCipher extends EncryptionAlgorithmInit {
+ NewTripleDESCipher() {
+ exists(Function f | this = f.getACall().getResult(0) |
+ f.hasQualifiedName("crypto/des", "NewTripleDESCipher")
+ )
+ }
+
+ override EncryptionAlgorithm getAlgorithm() { result.matchesName("TRIPLEDES") }
+ }
+ }
+
+ private module Md5 {
+ private class Sum extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum() { this.getTarget().hasQualifiedName("crypto/md5", "Sum") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("MD5") }
+ }
+
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("crypto/md5", "New") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("MD5") }
+ }
+ }
+
+ private module Rc4 {
+ private class CipherXORKeyStream extends CryptographicOperation::Range instanceof DataFlow::CallNode
+ {
+ CipherXORKeyStream() {
+ this.(DataFlow::MethodCallNode)
+ .getTarget()
+ .hasQualifiedName("crypto/rc4", "Cipher", "XORKeyStream")
+ }
+
+ override DataFlow::Node getInitialization() { result = this }
+
+ override EncryptionAlgorithm getAlgorithm() { result.matchesName("RC4") }
+
+ override DataFlow::Node getAnInput() { result = super.getArgument(1) }
+
+ override BlockMode getBlockMode() { none() }
+ }
+ }
+
+ /**
+ * Cryptographic operations from the `crypto/sha1` package.
+ */
+ private module Sha1 {
+ private class Sum extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum() { this.getTarget().hasQualifiedName("crypto/sha1", "Sum") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA1") }
+ }
+
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("crypto/sha1", "New") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA1") }
+ }
+ }
+
+ /**
+ * Cryptographic operations from the `crypto/sha256` package.
+ */
+ private module Sha256 {
+ private class Sum256 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum256() { this.getTarget().hasQualifiedName("crypto/sha256", "Sum256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA256") }
+ }
+
+ private class Sum224 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum224() { this.getTarget().hasQualifiedName("crypto/sha256", "Sum224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA224") }
+ }
+
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("crypto/sha256", "New") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA256") }
+ }
+
+ private class New224 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New224() { this.getTarget().hasQualifiedName("crypto/sha256", "New224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA224") }
+ }
+ }
+
+ private module Sha3 {
+ private class Sum224 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum224() { this.getTarget().hasQualifiedName("crypto/sha3", "Sum224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3224") }
+ }
+
+ private class Sum256 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum256() { this.getTarget().hasQualifiedName("crypto/sha3", "Sum256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3256") }
+ }
+
+ private class Sum384 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum384() { this.getTarget().hasQualifiedName("crypto/sha3", "Sum384") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3384") }
+ }
+
+ private class Sum512 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum512() { this.getTarget().hasQualifiedName("crypto/sha3", "Sum512") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3512") }
+ }
+
+ private class SumShake128 extends DirectHashOperation instanceof DataFlow::CallNode {
+ SumShake128() { this.getTarget().hasQualifiedName("crypto/sha3", "SumSHAKE128") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHAKE128") }
+ }
+
+ private class SumShake256 extends DirectHashOperation instanceof DataFlow::CallNode {
+ SumShake256() { this.getTarget().hasQualifiedName("crypto/sha3", "SumSHAKE256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHAKE256") }
+ }
+
+ private class New224 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New224() { this.getTarget().hasQualifiedName("crypto/sha3", "New224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3224") }
+ }
+
+ private class New256 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New256() { this.getTarget().hasQualifiedName("crypto/sha3", "New256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3256") }
+ }
+
+ private class New384 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New384() { this.getTarget().hasQualifiedName("crypto/sha3", "New384") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3384") }
+ }
+
+ private class New512 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New512() { this.getTarget().hasQualifiedName("crypto/sha3", "New512") }
- override Expr getInput() { result = this.getArgument(0).asExpr() }
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA3512") }
+ }
- override CryptographicAlgorithm getAlgorithm() {
- result.matchesName(this.getTarget().getPackage().getName())
+ private class NewShake128 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ NewShake128() {
+ this.getTarget().hasQualifiedName("crypto/sha3", ["NewCSHAKE128", "NewSHAKE128"])
+ }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHAKE128") }
+ }
+
+ private class NewShake256 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ NewShake256() {
+ this.getTarget().hasQualifiedName("crypto/sha3", ["NewCSHAKE256", "NewSHAKE256"])
+ }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHAKE256") }
+ }
+
+ private class ShakeWrite extends HashOperation instanceof DataFlow::MethodCallNode {
+ ShakeWrite() { this.getTarget().hasQualifiedName("crypto/sha3", "SHAKE", "Write") }
+
+ override HashAlgorithmInit getInitialization() { HashFlow::flow(result, super.getReceiver()) }
+
+ override HashingAlgorithm getAlgorithm() { result = this.getInitialization().getAlgorithm() }
+
+ override DataFlow::Node getAnInput() { result = super.getArgument(0) }
+ }
}
+
+ private module Sha512 {
+ private class Sum384 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum384() { this.getTarget().hasQualifiedName("crypto/sha512", "Sum384") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA384") }
+ }
+
+ private class Sum512 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum512() { this.getTarget().hasQualifiedName("crypto/sha512", "Sum512") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512") }
+ }
+
+ private class Sum512_224 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum512_224() { this.getTarget().hasQualifiedName("crypto/sha512", "Sum512_224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512224") }
+ }
+
+ private class Sum512_256 extends DirectHashOperation instanceof DataFlow::CallNode {
+ Sum512_256() { this.getTarget().hasQualifiedName("crypto/sha512", "Sum512_256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512256") }
+ }
+
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("crypto/sha512", "New") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512") }
+ }
+
+ private class New384 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New384() { this.getTarget().hasQualifiedName("crypto/sha512", "New384") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA384") }
+ }
+
+ private class New512_224 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New512_224() { this.getTarget().hasQualifiedName("crypto/sha512", "New512_224") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512224") }
+ }
+
+ private class New512_256 extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New512_256() { this.getTarget().hasQualifiedName("crypto/sha512", "New512_256") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("SHA512256") }
+ }
+ }
+
+ private module Cipher {
+ private class NewCBCEncrypter extends StdLibNewEncrypter {
+ NewCBCEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCBCEncrypter") }
+
+ override BlockMode getMode() { result = "CBC" }
+ }
+
+ private class NewCFBEncrypter extends StdLibNewEncrypter {
+ NewCFBEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCFBEncrypter") }
+
+ override BlockMode getMode() { result = "CFB" }
+ }
+
+ private class NewCTR extends StdLibNewEncrypter {
+ NewCTR() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCTR") }
+
+ override BlockMode getMode() { result = "CTR" }
+ }
+
+ private class NewGCM extends StdLibNewEncrypter {
+ NewGCM() {
+ exists(string name | this.getTarget().hasQualifiedName("crypto/cipher", name) |
+ name = ["NewGCM", "NewGCMWithNonceSize", "NewGCMWithRandomNonce", "NewGCMWithTagSize"]
+ )
+ }
+
+ override BlockMode getMode() { result = "GCM" }
+ }
+
+ private class NewOFB extends StdLibNewEncrypter {
+ NewOFB() { this.getTarget().hasQualifiedName("crypto/cipher", "NewOFB") }
+
+ override BlockMode getMode() { result = "OFB" }
+ }
+
+ private class AeadSeal extends EncryptionMethodCall {
+ AeadSeal() {
+ this.(DataFlow::MethodCallNode)
+ .getTarget()
+ .hasQualifiedName("crypto/cipher", "AEAD", "Seal") and
+ inputArg = 2
+ }
+ }
+
+ private class BlockEncrypt extends EncryptionMethodCall {
+ BlockEncrypt() {
+ this.(DataFlow::MethodCallNode)
+ .getTarget()
+ .hasQualifiedName("crypto/cipher", "Block", "Encrypt") and
+ inputArg = 1
+ }
+ }
+
+ private class BlockModeCryptBlocks extends EncryptionMethodCall {
+ BlockModeCryptBlocks() {
+ this.(DataFlow::MethodCallNode)
+ .getTarget()
+ .hasQualifiedName("crypto/cipher", "BlockMode", "CryptBlocks") and
+ inputArg = 1
+ }
+ }
+
+ private class StreamXORKeyStream extends EncryptionMethodCall {
+ StreamXORKeyStream() {
+ this.(DataFlow::MethodCallNode)
+ .getTarget()
+ .hasQualifiedName("crypto/cipher", "Stream", "XORKeyStream") and
+ inputArg = 1
+ }
+ }
+
+ private class StreamReader extends EncryptionOperation {
+ StreamReader() {
+ lookThroughPointerType(this.getType()).hasQualifiedName("crypto/cipher", "StreamReader") and
+ exists(DataFlow::Write w, DataFlow::Node base, Field f |
+ f.hasQualifiedName("crypto/cipher", "StreamReader", "S") and
+ w.writesField(base, f, encryptionFlowTarget) and
+ DataFlow::localFlow(base, this)
+ ) and
+ exists(DataFlow::Write w, DataFlow::Node base, Field f |
+ f.hasQualifiedName("crypto/cipher", "StreamReader", "R") and
+ w.writesField(base, f, inputNode) and
+ DataFlow::localFlow(base, this)
+ )
+ }
+ }
+
+ /**
+ * Limitation: StreamWriter wraps a Writer, so we need to look forward to
+ * where the Writer is written to. Currently this is done using local flow,
+ * so it only works within one function.
+ */
+ private class StreamWriter extends EncryptionOperation {
+ StreamWriter() {
+ lookThroughPointerType(this.getType()).hasQualifiedName("crypto/cipher", "StreamWriter") and
+ inputNode = this and
+ exists(DataFlow::Write w, DataFlow::Node base, Field f |
+ w.writesField(base, f, encryptionFlowTarget) and
+ f.hasQualifiedName("crypto/cipher", "StreamWriter", "S")
+ |
+ base = this or
+ TaintTracking::localTaint(base, this.(DataFlow::PostUpdateNode).getPreUpdateNode())
+ )
+ }
+ }
+ }
+}
+
+private module Hash {
+ private class HashSum extends HashOperation instanceof DataFlow::MethodCallNode {
+ HashSum() { this.getTarget().implements("hash", "Hash", "Sum") }
+
+ override HashAlgorithmInit getInitialization() { HashFlow::flow(result, super.getReceiver()) }
+
+ override HashingAlgorithm getAlgorithm() { result = this.getInitialization().getAlgorithm() }
+
+ override DataFlow::Node getAnInput() { result = super.getArgument(0) }
+ }
+}
+
+private DataFlow::Node getANonIoWriterPredecessor(DataFlow::Node node) {
+ node.getType().implements("io", "Writer") and
+ exists(DataFlow::Node pre | TaintTracking::localTaintStep(pre, node) |
+ if pre.getType().implements("io", "Writer")
+ then result = getANonIoWriterPredecessor(pre)
+ else result = pre
+ )
}
/**
- * A cryptographic operation from the `crypto/rc4` package.
+ * Taint flowing to an `io.Writer` (such as `hash.Hash` or `*sha3.SHAKE`) via
+ * its implementation of the `io.Writer` interface.
*/
-class Rc4 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
- Rc4() { this.getTarget().hasQualifiedName("crypto/rc4", "NewCipher") }
+private class FlowToIoWriter extends HashOperation instanceof DataFlow::Node {
+ HashAlgorithmInit init;
+ DataFlow::Node input;
+
+ FlowToIoWriter() {
+ this.getType().implements("io", "Writer") and
+ HashFlow::flow(init, this) and
+ // If we have `h.Write(taint)` or `io.WriteString(h, taint)` then it's
+ // the post-update node of `h` that gets tainted.
+ exists(DataFlow::PostUpdateNode pun | pun.getPreUpdateNode() = this |
+ input = getANonIoWriterPredecessor(pun)
+ )
+ }
+
+ override HashAlgorithmInit getInitialization() { result = init }
+
+ override HashingAlgorithm getAlgorithm() { result = this.getInitialization().getAlgorithm() }
+
+ override DataFlow::Node getAnInput() { result = input }
+}
+
+/**
+ * Currently only weak algorithms from the `golang.org/x/crypto` module are
+ * modeled here.
+ */
+private module GolangOrgXCrypto {
+ private module Md4 {
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("golang.org/x/crypto/md4", "New") }
+
+ override HashingAlgorithm getAlgorithm() { result.matchesName("MD4") }
+ }
+ }
- override Expr getInput() { result = this.getArgument(0).asExpr() }
+ private module Ripemd160 {
+ private class New extends HashAlgorithmInit instanceof DataFlow::CallNode {
+ New() { this.getTarget().hasQualifiedName("golang.org/x/crypto/ripemd160", "New") }
- override CryptographicAlgorithm getAlgorithm() {
- result.matchesName(this.getTarget().getPackage().getName())
+ override HashingAlgorithm getAlgorithm() { result.matchesName("RIPEMD160") }
+ }
}
}
diff --git a/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
index 6f40dfcc7ad0..4fbf77dda629 100644
--- a/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
+++ b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
@@ -1,17 +1,83 @@
#select
-| Crypto.go:21:25:21:27 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:21:25:21:27 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
-| Crypto.go:24:10:24:12 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:24:10:24:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
-| Crypto.go:27:16:27:18 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:27:16:27:18 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
-| Crypto.go:30:11:30:13 | buf | Crypto.go:18:9:18:16 | password | Crypto.go:30:11:30:13 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:18:9:18:16 | password | Sensitive data |
+| Crypto.go:36:21:36:28 | password | Crypto.go:36:21:36:28 | password | Crypto.go:36:21:36:28 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:36:21:36:28 | password | Sensitive data |
+| Crypto.go:41:22:41:29 | password | Crypto.go:41:22:41:29 | password | Crypto.go:41:22:41:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:41:22:41:29 | password | Sensitive data |
+| Crypto.go:46:22:46:29 | password | Crypto.go:46:22:46:29 | password | Crypto.go:46:22:46:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:46:22:46:29 | password | Sensitive data |
+| Crypto.go:51:22:51:29 | password | Crypto.go:51:22:51:29 | password | Crypto.go:51:22:51:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:51:22:51:29 | password | Sensitive data |
+| Crypto.go:56:22:56:29 | password | Crypto.go:56:22:56:29 | password | Crypto.go:56:22:56:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:56:22:56:29 | password | Sensitive data |
+| Crypto.go:61:32:61:39 | password | Crypto.go:61:32:61:39 | password | Crypto.go:61:32:61:39 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:61:32:61:39 | password | Sensitive data |
+| Crypto.go:66:30:66:37 | password | Crypto.go:66:30:66:37 | password | Crypto.go:66:30:66:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:66:30:66:37 | password | Sensitive data |
+| Crypto.go:68:59:68:83 | call to NewReader | Crypto.go:68:75:68:82 | password | Crypto.go:68:59:68:83 | call to NewReader | $@ is used in a weak cryptographic algorithm. | Crypto.go:68:75:68:82 | password | Sensitive data |
+| Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | Crypto.go:72:43:72:50 | password | Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | $@ is used in a weak cryptographic algorithm. | Crypto.go:72:43:72:50 | password | Sensitive data |
+| Crypto.go:78:30:78:37 | password | Crypto.go:78:30:78:37 | password | Crypto.go:78:30:78:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:78:30:78:37 | password | Sensitive data |
+| Crypto.go:83:30:83:37 | password | Crypto.go:83:30:83:37 | password | Crypto.go:83:30:83:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:83:30:83:37 | password | Sensitive data |
+| Crypto.go:91:21:91:33 | call to getPassword | Crypto.go:91:21:91:33 | call to getPassword | Crypto.go:91:21:91:33 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:91:21:91:33 | call to getPassword | Sensitive data |
+| Crypto.go:96:22:96:34 | call to getPassword | Crypto.go:96:22:96:34 | call to getPassword | Crypto.go:96:22:96:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:96:22:96:34 | call to getPassword | Sensitive data |
+| Crypto.go:101:22:101:34 | call to getPassword | Crypto.go:101:22:101:34 | call to getPassword | Crypto.go:101:22:101:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:101:22:101:34 | call to getPassword | Sensitive data |
+| Crypto.go:106:22:106:29 | password | Crypto.go:106:22:106:29 | password | Crypto.go:106:22:106:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:106:22:106:29 | password | Sensitive data |
+| Crypto.go:111:22:111:29 | password | Crypto.go:111:22:111:29 | password | Crypto.go:111:22:111:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:111:22:111:29 | password | Sensitive data |
+| Crypto.go:116:32:116:44 | call to getPassword | Crypto.go:116:32:116:44 | call to getPassword | Crypto.go:116:32:116:44 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:116:32:116:44 | call to getPassword | Sensitive data |
+| Crypto.go:121:30:121:42 | call to getPassword | Crypto.go:121:30:121:42 | call to getPassword | Crypto.go:121:30:121:42 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:121:30:121:42 | call to getPassword | Sensitive data |
+| Crypto.go:123:59:123:88 | call to NewReader | Crypto.go:123:75:123:87 | call to getPassword | Crypto.go:123:59:123:88 | call to NewReader | $@ is used in a weak cryptographic algorithm. | Crypto.go:123:75:123:87 | call to getPassword | Sensitive data |
+| Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | Crypto.go:127:43:127:55 | call to getPassword | Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | $@ is used in a weak cryptographic algorithm. | Crypto.go:127:43:127:55 | call to getPassword | Sensitive data |
+| Crypto.go:133:30:133:37 | password | Crypto.go:133:30:133:37 | password | Crypto.go:133:30:133:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:133:30:133:37 | password | Sensitive data |
+| Crypto.go:138:30:138:37 | password | Crypto.go:138:30:138:37 | password | Crypto.go:138:30:138:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:138:30:138:37 | password | Sensitive data |
+| Crypto.go:198:22:198:34 | call to getPassword | Crypto.go:198:22:198:34 | call to getPassword | Crypto.go:198:22:198:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:198:22:198:34 | call to getPassword | Sensitive data |
+| Crypto.go:205:8:205:10 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:205:8:205:10 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
+| Crypto.go:206:10:206:12 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:206:10:206:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
+| Crypto.go:207:20:207:33 | passwordString | Crypto.go:207:20:207:33 | passwordString | Crypto.go:207:20:207:33 | passwordString | $@ is used in a weak cryptographic algorithm. | Crypto.go:207:20:207:33 | passwordString | Sensitive data |
+| Crypto.go:208:10:208:12 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:208:10:208:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
+| Crypto.go:210:17:210:19 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:210:17:210:19 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
+| Crypto.go:211:11:211:13 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:211:11:211:13 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
edges
-| Crypto.go:18:9:18:16 | password | Crypto.go:21:25:21:27 | buf | provenance | |
-| Crypto.go:18:9:18:16 | password | Crypto.go:24:10:24:12 | buf | provenance | |
-| Crypto.go:18:9:18:16 | password | Crypto.go:27:16:27:18 | buf | provenance | |
-| Crypto.go:18:9:18:16 | password | Crypto.go:30:11:30:13 | buf | provenance | |
+| Crypto.go:68:75:68:82 | password | Crypto.go:68:59:68:83 | call to NewReader | provenance | MaD:1 |
+| Crypto.go:72:27:72:51 | call to NewReader | Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | provenance | MaD:2 |
+| Crypto.go:72:43:72:50 | password | Crypto.go:72:27:72:51 | call to NewReader | provenance | MaD:1 |
+| Crypto.go:123:75:123:87 | call to getPassword | Crypto.go:123:59:123:88 | call to NewReader | provenance | MaD:1 |
+| Crypto.go:127:27:127:56 | call to NewReader | Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | provenance | MaD:2 |
+| Crypto.go:127:43:127:55 | call to getPassword | Crypto.go:127:27:127:56 | call to NewReader | provenance | MaD:1 |
+| Crypto.go:202:9:202:16 | password | Crypto.go:205:8:205:10 | buf | provenance | |
+| Crypto.go:202:9:202:16 | password | Crypto.go:206:10:206:12 | buf | provenance | |
+| Crypto.go:202:9:202:16 | password | Crypto.go:208:10:208:12 | buf | provenance | |
+| Crypto.go:202:9:202:16 | password | Crypto.go:210:17:210:19 | buf | provenance | |
+| Crypto.go:202:9:202:16 | password | Crypto.go:211:11:211:13 | buf | provenance | |
+models
+| 1 | Summary: bytes; ; false; NewReader; ; ; Argument[0]; ReturnValue; taint; manual |
+| 2 | Summary: io; ; false; Copy; ; ; Argument[1]; Argument[0]; taint; manual |
nodes
-| Crypto.go:18:9:18:16 | password | semmle.label | password |
-| Crypto.go:21:25:21:27 | buf | semmle.label | buf |
-| Crypto.go:24:10:24:12 | buf | semmle.label | buf |
-| Crypto.go:27:16:27:18 | buf | semmle.label | buf |
-| Crypto.go:30:11:30:13 | buf | semmle.label | buf |
+| Crypto.go:36:21:36:28 | password | semmle.label | password |
+| Crypto.go:41:22:41:29 | password | semmle.label | password |
+| Crypto.go:46:22:46:29 | password | semmle.label | password |
+| Crypto.go:51:22:51:29 | password | semmle.label | password |
+| Crypto.go:56:22:56:29 | password | semmle.label | password |
+| Crypto.go:61:32:61:39 | password | semmle.label | password |
+| Crypto.go:66:30:66:37 | password | semmle.label | password |
+| Crypto.go:68:59:68:83 | call to NewReader | semmle.label | call to NewReader |
+| Crypto.go:68:75:68:82 | password | semmle.label | password |
+| Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | semmle.label | ctrStreamWriter [postupdate] |
+| Crypto.go:72:27:72:51 | call to NewReader | semmle.label | call to NewReader |
+| Crypto.go:72:43:72:50 | password | semmle.label | password |
+| Crypto.go:78:30:78:37 | password | semmle.label | password |
+| Crypto.go:83:30:83:37 | password | semmle.label | password |
+| Crypto.go:91:21:91:33 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:96:22:96:34 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:101:22:101:34 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:106:22:106:29 | password | semmle.label | password |
+| Crypto.go:111:22:111:29 | password | semmle.label | password |
+| Crypto.go:116:32:116:44 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:121:30:121:42 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:123:59:123:88 | call to NewReader | semmle.label | call to NewReader |
+| Crypto.go:123:75:123:87 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | semmle.label | ctrStreamWriter [postupdate] |
+| Crypto.go:127:27:127:56 | call to NewReader | semmle.label | call to NewReader |
+| Crypto.go:127:43:127:55 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:133:30:133:37 | password | semmle.label | password |
+| Crypto.go:138:30:138:37 | password | semmle.label | password |
+| Crypto.go:198:22:198:34 | call to getPassword | semmle.label | call to getPassword |
+| Crypto.go:202:9:202:16 | password | semmle.label | password |
+| Crypto.go:205:8:205:10 | buf | semmle.label | buf |
+| Crypto.go:206:10:206:12 | buf | semmle.label | buf |
+| Crypto.go:207:20:207:33 | passwordString | semmle.label | passwordString |
+| Crypto.go:208:10:208:12 | buf | semmle.label | buf |
+| Crypto.go:210:17:210:19 | buf | semmle.label | buf |
+| Crypto.go:211:11:211:13 | buf | semmle.label | buf |
subpaths
diff --git a/go/ql/test/query-tests/Security/CWE-327/Crypto.go b/go/ql/test/query-tests/Security/CWE-327/Crypto.go
index a58052df38d7..1a7afc35cb99 100644
--- a/go/ql/test/query-tests/Security/CWE-327/Crypto.go
+++ b/go/ql/test/query-tests/Security/CWE-327/Crypto.go
@@ -1,55 +1,254 @@
package main
import (
+ "bytes"
"crypto/aes"
+ "crypto/cipher"
"crypto/des"
"crypto/md5"
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
+ "crypto/sha3"
+ "crypto/sha512"
+ "io"
+ "os"
)
-func crypto() {
- public := []byte("hello")
+var dst []byte = make([]byte, 16)
+var password []byte = []byte("123456")
- password := []byte("123456")
+const passwordString string = "correct horse battery staple"
- // testing dataflow by passing into different variable
+var public []byte = []byte("hello")
+
+func getPassword() []byte {
+ return []byte("123456")
+}
+
+// Note that we do not alert on decryption as we may need to decrypt legacy formats
+
+func BlockCipherDes() {
+ // BAD, des is a weak crypto algorithm
+ block, _ := des.NewCipher(nil)
+
+ block.Encrypt(dst, public) // $ CryptographicOperation="DES. init from line 33."
+ block.Encrypt(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
+ block.Decrypt(dst, password)
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
+ gcm1.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
+ gcm1.Open(nil, nil, password, nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
+ gcm2.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
+ gcm2.Open(nil, nil, password, nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
+ gcm3.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
+ gcm3.Open(nil, nil, password, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
+ gcm4.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
+ gcm4.Open(nil, nil, password, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="DES. blockMode: CBC. init from lines 33,59."
+ cbcEncrypter.CryptBlocks(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CBC. init from lines 33,59."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, password)
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
+ ctrStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(password)} // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
+ io.Copy(ctrStreamWriter, bytes.NewReader(password)) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: CFB. init from lines 33,76."
+ cfbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CFB. init from lines 33,76."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: OFB. init from lines 33,81."
+ ofbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: OFB. init from lines 33,81."
+}
+
+func BlockCipherTripleDes() {
+ // BAD, triple des is a weak crypto algorithm and password is sensitive data
+ block, _ := des.NewTripleDESCipher(nil)
+
+ block.Encrypt(dst, public) // $ CryptographicOperation="TRIPLEDES. init from line 88."
+ block.Encrypt(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
+ block.Decrypt(dst, getPassword())
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm1.Seal(nil, nil, getPassword(), nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm1.Open(nil, nil, getPassword(), nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm2.Seal(nil, nil, getPassword(), nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm2.Open(nil, nil, getPassword(), nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm3.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm3.Open(nil, nil, password, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm4.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
+ gcm4.Open(nil, nil, password, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CBC. init from lines 114,88."
+ cbcEncrypter.CryptBlocks(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CBC. init from lines 114,88."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, getPassword())
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
+ ctrStream.XORKeyStream(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(getPassword())} // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
+ io.Copy(ctrStreamWriter, bytes.NewReader(getPassword())) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CFB. init from lines 131,88."
+ cfbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CFB. init from lines 131,88."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: OFB. init from lines 136,88."
+ ofbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: OFB. init from lines 136,88."
+}
+
+func BlockCipherAes() {
+ // GOOD, aes is a strong crypto algorithm
+ block, _ := aes.NewCipher(nil)
+
+ block.Encrypt(dst, public) // $ CryptographicOperation="AES. init from line 143."
+ block.Encrypt(dst, password) // $ CryptographicOperation="AES. init from line 143."
+ block.Decrypt(dst, password)
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm1.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm1.Open(nil, nil, password, nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm2.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm2.Open(nil, nil, password, nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm3.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm3.Open(nil, nil, password, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm4.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
+ gcm4.Open(nil, nil, password, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="AES. blockMode: CBC. init from lines 143,169."
+ cbcEncrypter.CryptBlocks(dst, password) // $ CryptographicOperation="AES. blockMode: CBC. init from lines 143,169."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, password)
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
+ ctrStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(password)} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
+ io.Copy(ctrStreamWriter, bytes.NewReader(password)) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: CFB. init from lines 143,186."
+ cfbStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: CFB. init from lines 143,186."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: OFB. init from lines 143,191."
+ ofbStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: OFB. init from lines 143,191."
+}
+
+func CipherRc4() {
+ c, _ := rc4.NewCipher(nil)
+ c.XORKeyStream(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="RC4. init from line 198."
+}
+
+func WeakHashes() {
buf := password // $ Source
- // BAD, des is a weak crypto algorithm and password is sensitive data
- des.NewTripleDESCipher(buf) // $ Alert
+ h := md5.New()
+ h.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
+ h.Write(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
+ io.WriteString(h, passwordString) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
+ md5.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 208."
+
+ sha1.New().Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="SHA1. init from line 210."
+ sha1.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="SHA1. init from line 211."
+}
+
+func StrongHashes() {
+ buf := password
+
+ sha256.New224().Sum(buf) // $ CryptographicOperation="SHA224. init from line 217."
+ sha256.Sum224(buf) // $ CryptographicOperation="SHA224. init from line 218."
- // BAD, md5 is a weak crypto algorithm and password is sensitive data
- md5.Sum(buf) // $ Alert
+ sha256.New().Sum(buf) // $ CryptographicOperation="SHA256. init from line 220."
+ sha256.Sum256(buf) // $ CryptographicOperation="SHA256. init from line 221."
- // BAD, rc4 is a weak crypto algorithm and password is sensitive data
- rc4.NewCipher(buf) // $ Alert
+ sha512.New().Sum(buf) // $ CryptographicOperation="SHA512. init from line 223."
+ sha512.Sum512(buf) // $ CryptographicOperation="SHA512. init from line 224."
- // BAD, sha1 is a weak crypto algorithm and password is sensitive data
- sha1.Sum(buf) // $ Alert
+ sha512.New384().Sum(buf) // $ CryptographicOperation="SHA384. init from line 226."
+ sha512.Sum384(buf) // $ CryptographicOperation="SHA384. init from line 227."
- // GOOD, password is sensitive data but aes is a strong crypto algorithm
- aes.NewCipher(buf)
+ sha512.New512_224().Sum(buf) // $ CryptographicOperation="SHA512224. init from line 229."
+ sha512.Sum512_224(buf) // $ CryptographicOperation="SHA512224. init from line 230."
- // GOOD, password is sensitive data but sha256 is a strong crypto algorithm
- sha256.Sum256(buf)
+ sha512.New512_256().Sum(buf) // $ CryptographicOperation="SHA512256. init from line 232."
+ sha512.Sum512_256(buf) // $ CryptographicOperation="SHA512256. init from line 233."
- // GOOD, des is a weak crypto algorithm but public is not sensitive data
- des.NewTripleDESCipher(public)
+ sha3.New224().Sum(buf) // $ CryptographicOperation="SHA3224. init from line 235."
+ sha3.Sum224(buf) // $ CryptographicOperation="SHA3224. init from line 236."
- // GOOD, md5 is a weak crypto algorithm but public is not sensitive data
- md5.Sum(public)
+ sha3.New256().Sum(buf) // $ CryptographicOperation="SHA3256. init from line 238."
+ sha3.Sum256(buf) // $ CryptographicOperation="SHA3256. init from line 239."
- // GOOD, rc4 is a weak crypto algorithm but public is not sensitive data
- rc4.NewCipher(public)
+ sha3.New384().Sum(buf) // $ CryptographicOperation="SHA3384. init from line 241."
+ sha3.Sum384(buf) // $ CryptographicOperation="SHA3384. init from line 242."
- // GOOD, sha1 is a weak crypto algorithm but public is not sensitive data
- sha1.Sum(public)
+ sha3.New512().Sum(buf) // $ CryptographicOperation="SHA3512. init from line 244."
+ sha3.Sum512(buf) // $ CryptographicOperation="SHA3512. init from line 245."
- // GOOD, aes is a strong crypto algorithm and public is not sensitive data
- aes.NewCipher(public)
+ sha3.NewSHAKE128().Write(buf) // $ CryptographicOperation="SHAKE128. init from line 247."
+ sha3.NewCSHAKE128(nil, nil).Write(buf) // $ CryptographicOperation="SHAKE128. init from line 248."
+ sha3.SumSHAKE128(buf, 100) // $ CryptographicOperation="SHAKE128. init from line 249."
- // GOOD, sha256 is a strong crypto algorithm and public is not sensitive data
- sha256.Sum256(public)
+ sha3.NewSHAKE256().Write(buf) // $ CryptographicOperation="SHAKE256. init from line 251."
+ sha3.NewCSHAKE256(nil, nil).Write(buf) // $ CryptographicOperation="SHAKE256. init from line 252."
+ sha3.SumSHAKE256(buf, 100) // $ CryptographicOperation="SHAKE256. init from line 253."
}
diff --git a/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.expected b/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.expected
new file mode 100644
index 000000000000..55e9aed2e93c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.expected
@@ -0,0 +1,2 @@
+testFailures
+invalidModelRow
diff --git a/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.ql b/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.ql
new file mode 100644
index 000000000000..ab096f9df2ac
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.ql
@@ -0,0 +1,47 @@
+import go
+import ModelValidation
+import utils.test.InlineExpectationsTest
+
+module Test implements TestSig {
+ string getARelevantTag() { result = "CryptographicOperation" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "CryptographicOperation" and
+ exists(
+ CryptographicOperation::Range ho, string algorithm, string initialization, string blockMode
+ |
+ algorithm = ho.getAlgorithm().toString() + "." and
+ (
+ blockMode = " blockMode: " + ho.getBlockMode().toString() + "."
+ or
+ not exists(ho.getBlockMode()) and blockMode = ""
+ ) and
+ exists(int c | c = count(ho.getInitialization()) |
+ c = 0 and initialization = ""
+ or
+ c = 1 and
+ initialization =
+ " init from line " +
+ strictconcat(DataFlow::Node init |
+ init = ho.getInitialization()
+ |
+ init.getStartLine().toString(), ","
+ ) + "."
+ or
+ c > 1 and
+ initialization =
+ " init from lines " +
+ strictconcat(DataFlow::Node init |
+ init = ho.getInitialization()
+ |
+ init.getStartLine().toString(), ","
+ ) + "."
+ ) and
+ ho.getLocation() = location and
+ element = ho.toString() and
+ value = "\"" + algorithm + blockMode + initialization + "\""
+ )
+ }
+}
+
+import MakeTest
diff --git a/go/ql/test/query-tests/Security/CWE-327/go.mod b/go/ql/test/query-tests/Security/CWE-327/go.mod
new file mode 100644
index 000000000000..bf42b84feefd
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/go.mod
@@ -0,0 +1,3 @@
+module test
+
+go 1.24
diff --git a/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll
index efcd870c724a..86392890cafb 100644
--- a/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll
+++ b/shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll
@@ -23,7 +23,8 @@ predicate isStrongHashingAlgorithm(string name) {
"BLAKE3",
//
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
- "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512",
+ "SHA224", "SHA256", "SHA384", "SHA512", "SHA512224", "SHA512256", "SHA3", "SHA3224",
+ "SHA3256", "SHA3384", "SHA3512",
// see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128
"SHAKE128", "SHAKE256",
// see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3
From b5271a6afe450b11ecfcf3e2866e344f880ef72a Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 31 Oct 2025 15:55:54 +0000
Subject: [PATCH 09/18] Make non-path query for encryption only
---
.../BrokenCryptoAlgorithmCustomizations.qll | 58 ----
.../security/BrokenCryptoAlgorithmQuery.qll | 43 ---
.../Security/CWE-327/BrokenCryptoAlgorithm.ql | 28 +-
.../CWE-327/BrokenCryptoAlgorithm.expected | 112 ++------
.../query-tests/Security/CWE-327/Crypto.go | 254 ------------------
.../Security/CWE-327/encryption.go | 167 ++++++++++++
6 files changed, 216 insertions(+), 446 deletions(-)
delete mode 100644 go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
delete mode 100644 go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
delete mode 100644 go/ql/test/query-tests/Security/CWE-327/Crypto.go
create mode 100644 go/ql/test/query-tests/Security/CWE-327/encryption.go
diff --git a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
deleted file mode 100644
index e5ac77fbb75f..000000000000
--- a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Provides default sources, sinks and sanitizers for reasoning about
- * sensitive information in weak cryptographic algorithms,
- * as well as extension points for adding your own.
- */
-
-import go
-private import semmle.go.security.SensitiveActions
-
-/**
- * Provides default sources, sinks and sanitizers for reasoning about
- * sensitive information in weak cryptographic algorithms,
- * as well as extension points for adding your own.
- */
-module BrokenCryptoAlgorithm {
- /**
- * A data flow source for sensitive information in broken or weak cryptographic algorithms.
- */
- abstract class Source extends DataFlow::Node { }
-
- /**
- * A data flow sink for sensitive information in broken or weak cryptographic algorithms.
- */
- abstract class Sink extends DataFlow::Node {
- /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
- abstract DataFlow::Node getInitialization();
- }
-
- /**
- * A sanitizer for sensitive information in broken or weak cryptographic algorithms.
- */
- abstract class Sanitizer extends DataFlow::Node { }
-
- /**
- * A sensitive source.
- */
- class SensitiveSource extends Source {
- SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
- }
-
- /**
- * An expression used by a broken or weak cryptographic algorithm.
- */
- class WeakCryptographicOperationSink extends Sink {
- CryptographicOperation application;
-
- WeakCryptographicOperationSink() {
- (
- application.getAlgorithm().isWeak()
- or
- application.getBlockMode().isWeak()
- ) and
- this = application.getAnInput()
- }
-
- override DataFlow::Node getInitialization() { result = application.getInitialization() }
- }
-}
diff --git a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll b/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
deleted file mode 100644
index ba24dcf57078..000000000000
--- a/go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Provides a taint tracking configuration for reasoning about
- * sensitive information in broken or weak cryptographic algorithms.
- *
- * Note, for performance reasons: only import this file if
- * `BrokenCryptoAlgorithm::Configuration` is needed, otherwise
- * `BrokenCryptoAlgorithmCustomizations` should be imported instead.
- */
-
-import go
-import BrokenCryptoAlgorithmCustomizations::BrokenCryptoAlgorithm
-
-/**
- * A taint tracking configuration for sensitive information in broken or weak cryptographic algorithms.
- *
- * This configuration identifies flows from `Source`s, which are sources of
- * sensitive data, to `Sink`s, which is an abstract class representing all
- * the places sensitive data may used in broken or weak cryptographic algorithms. Additional sources or sinks can be
- * added either by extending the relevant class, or by subclassing this configuration itself,
- * and amending the sources and sinks.
- */
-private module BrokenCryptoAlgorithmConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) { source instanceof Source }
-
- predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
-
- predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
-
- predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
-
- predicate observeDiffInformedIncrementalMode() { any() }
-
- Location getASelectedSinkLocation(DataFlow::Node sink) {
- result = sink.(Sink).getLocation()
- or
- result = sink.(Sink).getInitialization().getLocation()
- }
-}
-
-/**
- * Taint tracking flow for sensitive information in broken or weak cryptographic algorithms.
- */
-module BrokenCryptoAlgorithmFlow = TaintTracking::Global;
diff --git a/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
index 714a1cc7b3ec..67b2d0d6d2b4 100644
--- a/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
+++ b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
@@ -1,21 +1,33 @@
/**
* @name Use of a broken or weak cryptographic algorithm
* @description Using broken or weak cryptographic algorithms can compromise security.
- * @kind path-problem
+ * @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
- * @id go/weak-crypto-algorithm
+ * @id go/weak-cryptographic-algorithm
* @tags security
* external/cwe/cwe-327
* external/cwe/cwe-328
*/
import go
-import semmle.go.security.BrokenCryptoAlgorithmQuery
-import BrokenCryptoAlgorithmFlow::PathGraph
-from BrokenCryptoAlgorithmFlow::PathNode source, BrokenCryptoAlgorithmFlow::PathNode sink
-where BrokenCryptoAlgorithmFlow::flowPath(source, sink)
-select sink.getNode(), source, sink, "$@ is used in a weak cryptographic algorithm.",
- source.getNode(), "Sensitive data"
+from Cryptography::CryptographicOperation operation, string msgPrefix, DataFlow::Node init
+where
+ init = operation.getInitialization() and
+ // `init` may be a `BlockModeInit`, a `EncryptionAlgorithmInit`, or `operation` itself.
+ (
+ not init instanceof BlockModeInit and
+ exists(Cryptography::CryptographicAlgorithm algorithm |
+ algorithm = operation.getAlgorithm() and
+ algorithm.isWeak() and
+ msgPrefix = "The cryptographic algorithm " + algorithm.getName() and
+ not algorithm instanceof Cryptography::HashingAlgorithm
+ )
+ or
+ not init instanceof EncryptionAlgorithmInit and
+ operation.getBlockMode().isWeak() and
+ msgPrefix = "The block mode " + operation.getBlockMode()
+ )
+select operation, "$@ is broken or weak, and should not be used.", init, msgPrefix
diff --git a/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
index 4fbf77dda629..00eb67fea0ba 100644
--- a/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
+++ b/go/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected
@@ -1,83 +1,29 @@
-#select
-| Crypto.go:36:21:36:28 | password | Crypto.go:36:21:36:28 | password | Crypto.go:36:21:36:28 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:36:21:36:28 | password | Sensitive data |
-| Crypto.go:41:22:41:29 | password | Crypto.go:41:22:41:29 | password | Crypto.go:41:22:41:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:41:22:41:29 | password | Sensitive data |
-| Crypto.go:46:22:46:29 | password | Crypto.go:46:22:46:29 | password | Crypto.go:46:22:46:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:46:22:46:29 | password | Sensitive data |
-| Crypto.go:51:22:51:29 | password | Crypto.go:51:22:51:29 | password | Crypto.go:51:22:51:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:51:22:51:29 | password | Sensitive data |
-| Crypto.go:56:22:56:29 | password | Crypto.go:56:22:56:29 | password | Crypto.go:56:22:56:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:56:22:56:29 | password | Sensitive data |
-| Crypto.go:61:32:61:39 | password | Crypto.go:61:32:61:39 | password | Crypto.go:61:32:61:39 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:61:32:61:39 | password | Sensitive data |
-| Crypto.go:66:30:66:37 | password | Crypto.go:66:30:66:37 | password | Crypto.go:66:30:66:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:66:30:66:37 | password | Sensitive data |
-| Crypto.go:68:59:68:83 | call to NewReader | Crypto.go:68:75:68:82 | password | Crypto.go:68:59:68:83 | call to NewReader | $@ is used in a weak cryptographic algorithm. | Crypto.go:68:75:68:82 | password | Sensitive data |
-| Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | Crypto.go:72:43:72:50 | password | Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | $@ is used in a weak cryptographic algorithm. | Crypto.go:72:43:72:50 | password | Sensitive data |
-| Crypto.go:78:30:78:37 | password | Crypto.go:78:30:78:37 | password | Crypto.go:78:30:78:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:78:30:78:37 | password | Sensitive data |
-| Crypto.go:83:30:83:37 | password | Crypto.go:83:30:83:37 | password | Crypto.go:83:30:83:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:83:30:83:37 | password | Sensitive data |
-| Crypto.go:91:21:91:33 | call to getPassword | Crypto.go:91:21:91:33 | call to getPassword | Crypto.go:91:21:91:33 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:91:21:91:33 | call to getPassword | Sensitive data |
-| Crypto.go:96:22:96:34 | call to getPassword | Crypto.go:96:22:96:34 | call to getPassword | Crypto.go:96:22:96:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:96:22:96:34 | call to getPassword | Sensitive data |
-| Crypto.go:101:22:101:34 | call to getPassword | Crypto.go:101:22:101:34 | call to getPassword | Crypto.go:101:22:101:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:101:22:101:34 | call to getPassword | Sensitive data |
-| Crypto.go:106:22:106:29 | password | Crypto.go:106:22:106:29 | password | Crypto.go:106:22:106:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:106:22:106:29 | password | Sensitive data |
-| Crypto.go:111:22:111:29 | password | Crypto.go:111:22:111:29 | password | Crypto.go:111:22:111:29 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:111:22:111:29 | password | Sensitive data |
-| Crypto.go:116:32:116:44 | call to getPassword | Crypto.go:116:32:116:44 | call to getPassword | Crypto.go:116:32:116:44 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:116:32:116:44 | call to getPassword | Sensitive data |
-| Crypto.go:121:30:121:42 | call to getPassword | Crypto.go:121:30:121:42 | call to getPassword | Crypto.go:121:30:121:42 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:121:30:121:42 | call to getPassword | Sensitive data |
-| Crypto.go:123:59:123:88 | call to NewReader | Crypto.go:123:75:123:87 | call to getPassword | Crypto.go:123:59:123:88 | call to NewReader | $@ is used in a weak cryptographic algorithm. | Crypto.go:123:75:123:87 | call to getPassword | Sensitive data |
-| Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | Crypto.go:127:43:127:55 | call to getPassword | Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | $@ is used in a weak cryptographic algorithm. | Crypto.go:127:43:127:55 | call to getPassword | Sensitive data |
-| Crypto.go:133:30:133:37 | password | Crypto.go:133:30:133:37 | password | Crypto.go:133:30:133:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:133:30:133:37 | password | Sensitive data |
-| Crypto.go:138:30:138:37 | password | Crypto.go:138:30:138:37 | password | Crypto.go:138:30:138:37 | password | $@ is used in a weak cryptographic algorithm. | Crypto.go:138:30:138:37 | password | Sensitive data |
-| Crypto.go:198:22:198:34 | call to getPassword | Crypto.go:198:22:198:34 | call to getPassword | Crypto.go:198:22:198:34 | call to getPassword | $@ is used in a weak cryptographic algorithm. | Crypto.go:198:22:198:34 | call to getPassword | Sensitive data |
-| Crypto.go:205:8:205:10 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:205:8:205:10 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
-| Crypto.go:206:10:206:12 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:206:10:206:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
-| Crypto.go:207:20:207:33 | passwordString | Crypto.go:207:20:207:33 | passwordString | Crypto.go:207:20:207:33 | passwordString | $@ is used in a weak cryptographic algorithm. | Crypto.go:207:20:207:33 | passwordString | Sensitive data |
-| Crypto.go:208:10:208:12 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:208:10:208:12 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
-| Crypto.go:210:17:210:19 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:210:17:210:19 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
-| Crypto.go:211:11:211:13 | buf | Crypto.go:202:9:202:16 | password | Crypto.go:211:11:211:13 | buf | $@ is used in a weak cryptographic algorithm. | Crypto.go:202:9:202:16 | password | Sensitive data |
-edges
-| Crypto.go:68:75:68:82 | password | Crypto.go:68:59:68:83 | call to NewReader | provenance | MaD:1 |
-| Crypto.go:72:27:72:51 | call to NewReader | Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | provenance | MaD:2 |
-| Crypto.go:72:43:72:50 | password | Crypto.go:72:27:72:51 | call to NewReader | provenance | MaD:1 |
-| Crypto.go:123:75:123:87 | call to getPassword | Crypto.go:123:59:123:88 | call to NewReader | provenance | MaD:1 |
-| Crypto.go:127:27:127:56 | call to NewReader | Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | provenance | MaD:2 |
-| Crypto.go:127:43:127:55 | call to getPassword | Crypto.go:127:27:127:56 | call to NewReader | provenance | MaD:1 |
-| Crypto.go:202:9:202:16 | password | Crypto.go:205:8:205:10 | buf | provenance | |
-| Crypto.go:202:9:202:16 | password | Crypto.go:206:10:206:12 | buf | provenance | |
-| Crypto.go:202:9:202:16 | password | Crypto.go:208:10:208:12 | buf | provenance | |
-| Crypto.go:202:9:202:16 | password | Crypto.go:210:17:210:19 | buf | provenance | |
-| Crypto.go:202:9:202:16 | password | Crypto.go:211:11:211:13 | buf | provenance | |
-models
-| 1 | Summary: bytes; ; false; NewReader; ; ; Argument[0]; ReturnValue; taint; manual |
-| 2 | Summary: io; ; false; Copy; ; ; Argument[1]; Argument[0]; taint; manual |
-nodes
-| Crypto.go:36:21:36:28 | password | semmle.label | password |
-| Crypto.go:41:22:41:29 | password | semmle.label | password |
-| Crypto.go:46:22:46:29 | password | semmle.label | password |
-| Crypto.go:51:22:51:29 | password | semmle.label | password |
-| Crypto.go:56:22:56:29 | password | semmle.label | password |
-| Crypto.go:61:32:61:39 | password | semmle.label | password |
-| Crypto.go:66:30:66:37 | password | semmle.label | password |
-| Crypto.go:68:59:68:83 | call to NewReader | semmle.label | call to NewReader |
-| Crypto.go:68:75:68:82 | password | semmle.label | password |
-| Crypto.go:72:10:72:24 | ctrStreamWriter [postupdate] | semmle.label | ctrStreamWriter [postupdate] |
-| Crypto.go:72:27:72:51 | call to NewReader | semmle.label | call to NewReader |
-| Crypto.go:72:43:72:50 | password | semmle.label | password |
-| Crypto.go:78:30:78:37 | password | semmle.label | password |
-| Crypto.go:83:30:83:37 | password | semmle.label | password |
-| Crypto.go:91:21:91:33 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:96:22:96:34 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:101:22:101:34 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:106:22:106:29 | password | semmle.label | password |
-| Crypto.go:111:22:111:29 | password | semmle.label | password |
-| Crypto.go:116:32:116:44 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:121:30:121:42 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:123:59:123:88 | call to NewReader | semmle.label | call to NewReader |
-| Crypto.go:123:75:123:87 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:127:10:127:24 | ctrStreamWriter [postupdate] | semmle.label | ctrStreamWriter [postupdate] |
-| Crypto.go:127:27:127:56 | call to NewReader | semmle.label | call to NewReader |
-| Crypto.go:127:43:127:55 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:133:30:133:37 | password | semmle.label | password |
-| Crypto.go:138:30:138:37 | password | semmle.label | password |
-| Crypto.go:198:22:198:34 | call to getPassword | semmle.label | call to getPassword |
-| Crypto.go:202:9:202:16 | password | semmle.label | password |
-| Crypto.go:205:8:205:10 | buf | semmle.label | buf |
-| Crypto.go:206:10:206:12 | buf | semmle.label | buf |
-| Crypto.go:207:20:207:33 | passwordString | semmle.label | passwordString |
-| Crypto.go:208:10:208:12 | buf | semmle.label | buf |
-| Crypto.go:210:17:210:19 | buf | semmle.label | buf |
-| Crypto.go:211:11:211:13 | buf | semmle.label | buf |
-subpaths
+| encryption.go:30:2:30:36 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:34:2:34:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:38:2:38:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:42:2:42:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:46:2:46:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:50:2:50:47 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:54:2:54:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:56:22:56:91 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:59:21:59:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:59:22:59:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:59:22:59:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:60:10:60:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:65:2:65:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:69:2:69:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
+| encryption.go:76:2:76:32 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:80:2:80:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:84:2:84:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:88:2:88:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:92:2:92:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:96:2:96:43 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:100:2:100:41 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:102:22:102:87 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:105:21:105:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:105:22:105:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:105:22:105:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:106:10:106:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:111:2:111:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:115:2:115:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
+| encryption.go:166:2:166:33 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:166:2:166:33 | call to XORKeyStream | The cryptographic algorithm RC4 |
diff --git a/go/ql/test/query-tests/Security/CWE-327/Crypto.go b/go/ql/test/query-tests/Security/CWE-327/Crypto.go
deleted file mode 100644
index 1a7afc35cb99..000000000000
--- a/go/ql/test/query-tests/Security/CWE-327/Crypto.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package main
-
-import (
- "bytes"
- "crypto/aes"
- "crypto/cipher"
- "crypto/des"
- "crypto/md5"
- "crypto/rc4"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/sha3"
- "crypto/sha512"
- "io"
- "os"
-)
-
-var dst []byte = make([]byte, 16)
-var password []byte = []byte("123456")
-
-const passwordString string = "correct horse battery staple"
-
-var public []byte = []byte("hello")
-
-func getPassword() []byte {
- return []byte("123456")
-}
-
-// Note that we do not alert on decryption as we may need to decrypt legacy formats
-
-func BlockCipherDes() {
- // BAD, des is a weak crypto algorithm
- block, _ := des.NewCipher(nil)
-
- block.Encrypt(dst, public) // $ CryptographicOperation="DES. init from line 33."
- block.Encrypt(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
- block.Decrypt(dst, password)
-
- gcm1, _ := cipher.NewGCM(block)
- gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
- gcm1.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
- gcm1.Open(nil, nil, password, nil)
-
- gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
- gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
- gcm2.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
- gcm2.Open(nil, nil, password, nil)
-
- gcm3, _ := cipher.NewGCMWithRandomNonce(block)
- gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
- gcm3.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
- gcm3.Open(nil, nil, password, nil)
-
- gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
- gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="DES. init from line 33."
- gcm4.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. init from line 33."
- gcm4.Open(nil, nil, password, nil)
-
- cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
- cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="DES. blockMode: CBC. init from lines 33,59."
- cbcEncrypter.CryptBlocks(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CBC. init from lines 33,59."
- cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, password)
-
- ctrStream := cipher.NewCTR(block, nil)
- ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
- ctrStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
-
- ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(password)} // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
- io.Copy(os.Stdout, ctrStreamReader)
-
- ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
- io.Copy(ctrStreamWriter, bytes.NewReader(password)) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 33,64."
-
- // deprecated
-
- cfbStream := cipher.NewCFBEncrypter(block, nil)
- cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: CFB. init from lines 33,76."
- cfbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: CFB. init from lines 33,76."
- cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
-
- ofbStream := cipher.NewOFB(block, nil)
- ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="DES. blockMode: OFB. init from lines 33,81."
- ofbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="DES. blockMode: OFB. init from lines 33,81."
-}
-
-func BlockCipherTripleDes() {
- // BAD, triple des is a weak crypto algorithm and password is sensitive data
- block, _ := des.NewTripleDESCipher(nil)
-
- block.Encrypt(dst, public) // $ CryptographicOperation="TRIPLEDES. init from line 88."
- block.Encrypt(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
- block.Decrypt(dst, getPassword())
-
- gcm1, _ := cipher.NewGCM(block)
- gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
- gcm1.Seal(nil, nil, getPassword(), nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
- gcm1.Open(nil, nil, getPassword(), nil)
-
- gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
- gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
- gcm2.Seal(nil, nil, getPassword(), nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
- gcm2.Open(nil, nil, getPassword(), nil)
-
- gcm3, _ := cipher.NewGCMWithRandomNonce(block)
- gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
- gcm3.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
- gcm3.Open(nil, nil, password, nil)
-
- gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
- gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="TRIPLEDES. init from line 88."
- gcm4.Seal(nil, nil, password, nil) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. init from line 88."
- gcm4.Open(nil, nil, password, nil)
-
- cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
- cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CBC. init from lines 114,88."
- cbcEncrypter.CryptBlocks(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CBC. init from lines 114,88."
- cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, getPassword())
-
- ctrStream := cipher.NewCTR(block, nil)
- ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
- ctrStream.XORKeyStream(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
-
- ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(getPassword())} // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
- io.Copy(os.Stdout, ctrStreamReader)
-
- ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
- io.Copy(ctrStreamWriter, bytes.NewReader(getPassword())) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 119,88."
-
- // deprecated
-
- cfbStream := cipher.NewCFBEncrypter(block, nil)
- cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: CFB. init from lines 131,88."
- cfbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CFB. init from lines 131,88."
- cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
-
- ofbStream := cipher.NewOFB(block, nil)
- ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="TRIPLEDES. blockMode: OFB. init from lines 136,88."
- ofbStream.XORKeyStream(dst, password) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="TRIPLEDES. blockMode: OFB. init from lines 136,88."
-}
-
-func BlockCipherAes() {
- // GOOD, aes is a strong crypto algorithm
- block, _ := aes.NewCipher(nil)
-
- block.Encrypt(dst, public) // $ CryptographicOperation="AES. init from line 143."
- block.Encrypt(dst, password) // $ CryptographicOperation="AES. init from line 143."
- block.Decrypt(dst, password)
-
- gcm1, _ := cipher.NewGCM(block)
- gcm1.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm1.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm1.Open(nil, nil, password, nil)
-
- gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
- gcm2.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm2.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm2.Open(nil, nil, password, nil)
-
- gcm3, _ := cipher.NewGCMWithRandomNonce(block)
- gcm3.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm3.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm3.Open(nil, nil, password, nil)
-
- gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
- gcm4.Seal(nil, nil, public, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm4.Seal(nil, nil, password, nil) // $ CryptographicOperation="AES. init from line 143."
- gcm4.Open(nil, nil, password, nil)
-
- cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
- cbcEncrypter.CryptBlocks(dst, public) // $ CryptographicOperation="AES. blockMode: CBC. init from lines 143,169."
- cbcEncrypter.CryptBlocks(dst, password) // $ CryptographicOperation="AES. blockMode: CBC. init from lines 143,169."
- cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, password)
-
- ctrStream := cipher.NewCTR(block, nil)
- ctrStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
- ctrStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
-
- ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(password)} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
- io.Copy(os.Stdout, ctrStreamReader)
-
- ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
- io.Copy(ctrStreamWriter, bytes.NewReader(password)) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 143,174."
-
- // deprecated
-
- cfbStream := cipher.NewCFBEncrypter(block, nil)
- cfbStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: CFB. init from lines 143,186."
- cfbStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: CFB. init from lines 143,186."
- cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, password)
-
- ofbStream := cipher.NewOFB(block, nil)
- ofbStream.XORKeyStream(dst, public) // $ CryptographicOperation="AES. blockMode: OFB. init from lines 143,191."
- ofbStream.XORKeyStream(dst, password) // $ CryptographicOperation="AES. blockMode: OFB. init from lines 143,191."
-}
-
-func CipherRc4() {
- c, _ := rc4.NewCipher(nil)
- c.XORKeyStream(dst, getPassword()) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="RC4. init from line 198."
-}
-
-func WeakHashes() {
- buf := password // $ Source
-
- h := md5.New()
- h.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
- h.Write(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
- io.WriteString(h, passwordString) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 204."
- md5.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="MD5. init from line 208."
-
- sha1.New().Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="SHA1. init from line 210."
- sha1.Sum(buf) // $ Alert[go/weak-crypto-algorithm] CryptographicOperation="SHA1. init from line 211."
-}
-
-func StrongHashes() {
- buf := password
-
- sha256.New224().Sum(buf) // $ CryptographicOperation="SHA224. init from line 217."
- sha256.Sum224(buf) // $ CryptographicOperation="SHA224. init from line 218."
-
- sha256.New().Sum(buf) // $ CryptographicOperation="SHA256. init from line 220."
- sha256.Sum256(buf) // $ CryptographicOperation="SHA256. init from line 221."
-
- sha512.New().Sum(buf) // $ CryptographicOperation="SHA512. init from line 223."
- sha512.Sum512(buf) // $ CryptographicOperation="SHA512. init from line 224."
-
- sha512.New384().Sum(buf) // $ CryptographicOperation="SHA384. init from line 226."
- sha512.Sum384(buf) // $ CryptographicOperation="SHA384. init from line 227."
-
- sha512.New512_224().Sum(buf) // $ CryptographicOperation="SHA512224. init from line 229."
- sha512.Sum512_224(buf) // $ CryptographicOperation="SHA512224. init from line 230."
-
- sha512.New512_256().Sum(buf) // $ CryptographicOperation="SHA512256. init from line 232."
- sha512.Sum512_256(buf) // $ CryptographicOperation="SHA512256. init from line 233."
-
- sha3.New224().Sum(buf) // $ CryptographicOperation="SHA3224. init from line 235."
- sha3.Sum224(buf) // $ CryptographicOperation="SHA3224. init from line 236."
-
- sha3.New256().Sum(buf) // $ CryptographicOperation="SHA3256. init from line 238."
- sha3.Sum256(buf) // $ CryptographicOperation="SHA3256. init from line 239."
-
- sha3.New384().Sum(buf) // $ CryptographicOperation="SHA3384. init from line 241."
- sha3.Sum384(buf) // $ CryptographicOperation="SHA3384. init from line 242."
-
- sha3.New512().Sum(buf) // $ CryptographicOperation="SHA3512. init from line 244."
- sha3.Sum512(buf) // $ CryptographicOperation="SHA3512. init from line 245."
-
- sha3.NewSHAKE128().Write(buf) // $ CryptographicOperation="SHAKE128. init from line 247."
- sha3.NewCSHAKE128(nil, nil).Write(buf) // $ CryptographicOperation="SHAKE128. init from line 248."
- sha3.SumSHAKE128(buf, 100) // $ CryptographicOperation="SHAKE128. init from line 249."
-
- sha3.NewSHAKE256().Write(buf) // $ CryptographicOperation="SHAKE256. init from line 251."
- sha3.NewCSHAKE256(nil, nil).Write(buf) // $ CryptographicOperation="SHAKE256. init from line 252."
- sha3.SumSHAKE256(buf, 100) // $ CryptographicOperation="SHAKE256. init from line 253."
-}
diff --git a/go/ql/test/query-tests/Security/CWE-327/encryption.go b/go/ql/test/query-tests/Security/CWE-327/encryption.go
new file mode 100644
index 000000000000..2a1bd53440b8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/encryption.go
@@ -0,0 +1,167 @@
+package main
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/rc4"
+ "io"
+ "os"
+)
+
+var dst []byte = make([]byte, 16)
+var secretByteSlice []byte = []byte("")
+
+const secretString string = ""
+
+var public []byte = []byte("")
+
+func getUserID() []byte {
+ return []byte("")
+}
+
+// Note that we do not alert on decryption as we may need to decrypt legacy formats
+
+func BlockCipherDes() {
+ // BAD, des is a weak crypto algorithm
+ block, _ := des.NewCipher(nil)
+
+ block.Encrypt(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. init from line 28."
+ block.Decrypt(dst, secretByteSlice)
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. init from line 28."
+ gcm1.Open(nil, nil, secretByteSlice, nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. init from line 28."
+ gcm2.Open(nil, nil, secretByteSlice, nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. init from line 28."
+ gcm3.Open(nil, nil, secretByteSlice, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. init from line 28."
+ gcm4.Open(nil, nil, secretByteSlice, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CBC. init from lines 28,49."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, secretByteSlice)
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 28,53."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(secretByteSlice)} // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 28,53."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 28,53."
+ io.Copy(ctrStreamWriter, bytes.NewReader(secretByteSlice)) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CTR. init from lines 28,53."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: CFB. init from lines 28,64."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, secretByteSlice)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="DES. blockMode: OFB. init from lines 28,68."
+}
+
+func BlockCipherTripleDes() {
+ // BAD, triple des is a weak crypto algorithm and secretByteSlice is sensitive data
+ block, _ := des.NewTripleDESCipher(nil)
+
+ block.Encrypt(dst, getUserID()) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. init from line 74."
+ block.Decrypt(dst, getUserID())
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, getUserID(), nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. init from line 74."
+ gcm1.Open(nil, nil, getUserID(), nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, getUserID(), nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. init from line 74."
+ gcm2.Open(nil, nil, getUserID(), nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. init from line 74."
+ gcm3.Open(nil, nil, secretByteSlice, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, secretByteSlice, nil) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. init from line 74."
+ gcm4.Open(nil, nil, secretByteSlice, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, getUserID()) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CBC. init from lines 74,95."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, getUserID())
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, getUserID()) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 74,99."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(getUserID())} // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 74,99."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 74,99."
+ io.Copy(ctrStreamWriter, bytes.NewReader(getUserID())) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CTR. init from lines 74,99."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: CFB. init from lines 110,74."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, secretByteSlice)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, secretByteSlice) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="TRIPLEDES. blockMode: OFB. init from lines 114,74."
+}
+
+func BlockCipherAes() {
+ // GOOD, aes is a strong crypto algorithm
+ block, _ := aes.NewCipher(nil)
+
+ block.Encrypt(dst, secretByteSlice) // $ CryptographicOperation="AES. init from line 120."
+ block.Decrypt(dst, secretByteSlice)
+
+ gcm1, _ := cipher.NewGCM(block)
+ gcm1.Seal(nil, nil, secretByteSlice, nil) // $ CryptographicOperation="AES. init from line 120."
+ gcm1.Open(nil, nil, secretByteSlice, nil)
+
+ gcm2, _ := cipher.NewGCMWithNonceSize(block, 12)
+ gcm2.Seal(nil, nil, secretByteSlice, nil) // $ CryptographicOperation="AES. init from line 120."
+ gcm2.Open(nil, nil, secretByteSlice, nil)
+
+ gcm3, _ := cipher.NewGCMWithRandomNonce(block)
+ gcm3.Seal(nil, nil, secretByteSlice, nil) // $ CryptographicOperation="AES. init from line 120."
+ gcm3.Open(nil, nil, secretByteSlice, nil)
+
+ gcm4, _ := cipher.NewGCMWithTagSize(block, 12)
+ gcm4.Seal(nil, nil, secretByteSlice, nil) // $ CryptographicOperation="AES. init from line 120."
+ gcm4.Open(nil, nil, secretByteSlice, nil)
+
+ cbcEncrypter := cipher.NewCBCEncrypter(block, nil)
+ cbcEncrypter.CryptBlocks(dst, secretByteSlice) // $ CryptographicOperation="AES. blockMode: CBC. init from lines 120,141."
+ cipher.NewCBCDecrypter(block, nil).CryptBlocks(dst, secretByteSlice)
+
+ ctrStream := cipher.NewCTR(block, nil)
+ ctrStream.XORKeyStream(dst, secretByteSlice) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 120,145."
+
+ ctrStreamReader := &cipher.StreamReader{S: ctrStream, R: bytes.NewReader(secretByteSlice)} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 120,145."
+ io.Copy(os.Stdout, ctrStreamReader)
+
+ ctrStreamWriter := &cipher.StreamWriter{S: ctrStream, W: os.Stdout} // $ CryptographicOperation="AES. blockMode: CTR. init from lines 120,145."
+ io.Copy(ctrStreamWriter, bytes.NewReader(secretByteSlice)) // $ CryptographicOperation="AES. blockMode: CTR. init from lines 120,145."
+
+ // deprecated
+
+ cfbStream := cipher.NewCFBEncrypter(block, nil)
+ cfbStream.XORKeyStream(dst, secretByteSlice) // $ CryptographicOperation="AES. blockMode: CFB. init from lines 120,156."
+ cipher.NewCFBDecrypter(block, nil).XORKeyStream(dst, secretByteSlice)
+
+ ofbStream := cipher.NewOFB(block, nil)
+ ofbStream.XORKeyStream(dst, secretByteSlice) // $ CryptographicOperation="AES. blockMode: OFB. init from lines 120,160."
+}
+
+func CipherRc4() {
+ c, _ := rc4.NewCipher(nil)
+ c.XORKeyStream(dst, getUserID()) // $ Alert[go/weak-cryptographic-algorithm] CryptographicOperation="RC4. init from line 166."
+}
From 099dda128561ce349aa4041e1548405a32b48645 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 31 Oct 2025 15:56:18 +0000
Subject: [PATCH 10/18] Add query for hashing sensitive data with weak hashing
algorithm
---
...WeakSensitiveDataHashingCustomizations.qll | 172 ++++++++++++++++++
.../CWE-327/WeakSensitiveDataHashing.qhelp | 104 +++++++++++
.../CWE-327/WeakSensitiveDataHashing.ql | 114 ++++++++++++
.../CWE-327/WeakSensitiveDataHashing.expected | 22 +++
.../CWE-327/WeakSensitiveDataHashing.qlref | 4 +
.../test/query-tests/Security/CWE-327/go.mod | 4 +-
.../query-tests/Security/CWE-327/hashing.go | 81 +++++++++
.../vendor/golang.org/x/crypto/md4/stub.go | 16 ++
.../golang.org/x/crypto/ripemd160/stub.go | 16 ++
.../Security/CWE-327/vendor/modules.txt | 4 +
10 files changed, 536 insertions(+), 1 deletion(-)
create mode 100644 go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
create mode 100644 go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
create mode 100644 go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
create mode 100644 go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.expected
create mode 100644 go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.qlref
create mode 100644 go/ql/test/query-tests/Security/CWE-327/hashing.go
create mode 100644 go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/md4/stub.go
create mode 100644 go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/ripemd160/stub.go
create mode 100644 go/ql/test/query-tests/Security/CWE-327/vendor/modules.txt
diff --git a/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll b/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
new file mode 100644
index 000000000000..f03b93eb7c2e
--- /dev/null
+++ b/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
@@ -0,0 +1,172 @@
+/**
+ * Provides default sources, sinks and sanitizers for detecting "use of a
+ * broken or weak cryptographic hashing algorithm on sensitive data"
+ * vulnerabilities, as well as extension points for adding your own. This is
+ * divided into two general cases:
+ * - hashing sensitive data
+ * - hashing passwords (which requires the hashing algorithm to be
+ * sufficiently computationally expensive in addition to other requirements)
+ */
+
+import go
+import semmle.go.dataflow.internal.DataFlowPrivate
+private import semmle.go.security.SensitiveActions
+
+/**
+ * Provides default sources, sinks and sanitizers for detecting "use of a broken or weak
+ * cryptographic hashing algorithm on sensitive data" vulnerabilities on sensitive data that does
+ * NOT require computationally expensive hashing, as well as extension points for adding your own.
+ *
+ * Also see the `ComputationallyExpensiveHashFunction` module.
+ */
+module NormalHashFunction {
+ /**
+ * A data flow source for "use of a broken or weak cryptographic hashing algorithm on sensitive
+ * data" vulnerabilities that does not require computationally expensive hashing. That is, a
+ * piece of sensitive data that is not a password.
+ */
+ abstract class Source extends DataFlow::Node {
+ Source() { not this instanceof ComputationallyExpensiveHashFunction::Source }
+
+ /**
+ * Gets the classification of the sensitive data.
+ */
+ abstract string getClassification();
+ }
+
+ /**
+ * A data flow sink for "use of a broken or weak cryptographic hashing algorithm on sensitive
+ * data" vulnerabilities that applies to data that does not require computationally expensive
+ * hashing. That is, a broken or weak hashing algorithm.
+ */
+ abstract class Sink extends DataFlow::Node {
+ /**
+ * Gets the name of the weak hashing algorithm.
+ */
+ abstract string getAlgorithmName();
+ }
+
+ /**
+ * A barrier for "use of a broken or weak cryptographic hashing algorithm on sensitive data"
+ * vulnerabilities that applies to data that does not require computationally expensive hashing.
+ */
+ abstract class Barrier extends DataFlow::Node { }
+
+ /**
+ * A flow source modeled by the `SensitiveData` library.
+ */
+ class SensitiveDataAsSource extends Source {
+ SensitiveExpr::Classification classification;
+
+ SensitiveDataAsSource() {
+ classification = this.asExpr().(SensitiveExpr).getClassification() and
+ not classification = SensitiveExpr::password() and // (covered in ComputationallyExpensiveHashFunction)
+ not classification = SensitiveExpr::id() // (not accurate enough)
+ }
+
+ override SensitiveExpr::Classification getClassification() { result = classification }
+ }
+
+ /**
+ * A flow sink modeled by the `Cryptography` module.
+ */
+ class WeakHashingOperationInputAsSink extends Sink {
+ Cryptography::HashingAlgorithm algorithm;
+
+ WeakHashingOperationInputAsSink() {
+ exists(Cryptography::CryptographicOperation operation |
+ algorithm.isWeak() and
+ algorithm = operation.getAlgorithm() and
+ this = operation.getAnInput()
+ )
+ }
+
+ override string getAlgorithmName() { result = algorithm.getName() }
+ }
+}
+
+/**
+ * Provides default sources, sinks and sanitizers for detecting "use of a broken or weak
+ * cryptographic hashing algorithm on sensitive data" vulnerabilities on sensitive data that DOES
+ * require computationally expensive hashing, as well as extension points for adding your own.
+ *
+ * Also see the `NormalHashFunction` module.
+ */
+module ComputationallyExpensiveHashFunction {
+ /**
+ * A data flow source for "use of a broken or weak cryptographic hashing algorithm on sensitive
+ * data" vulnerabilities that does require computationally expensive hashing. That is, a
+ * password.
+ */
+ abstract class Source extends DataFlow::Node {
+ /**
+ * Gets the classification of the sensitive data.
+ */
+ abstract string getClassification();
+ }
+
+ /**
+ * A data flow sink for "use of a broken or weak cryptographic hashing algorithm on sensitive
+ * data" vulnerabilities that applies to data that does require computationally expensive
+ * hashing. That is, a broken or weak hashing algorithm or one that is not computationally
+ * expensive enough for password hashing.
+ */
+ abstract class Sink extends DataFlow::Node {
+ /**
+ * Gets the name of the weak hashing algorithm.
+ */
+ abstract string getAlgorithmName();
+
+ /**
+ * Holds if this sink is for a computationally expensive hash function (meaning that hash
+ * function is just weak in some other regard.
+ */
+ abstract predicate isComputationallyExpensive();
+ }
+
+ /**
+ * A barrier for "use of a broken or weak cryptographic hashing algorithm on sensitive data"
+ * vulnerabilities that applies to data that does require computationally expensive hashing.
+ */
+ abstract class Barrier extends DataFlow::Node { }
+
+ /**
+ * A flow source modeled by the `SensitiveData` library.
+ */
+ class PasswordAsSource extends Source {
+ SensitiveExpr::Classification classification;
+
+ PasswordAsSource() {
+ classification = this.asExpr().(SensitiveExpr).getClassification() and
+ classification = SensitiveExpr::password()
+ }
+
+ override SensitiveExpr::Classification getClassification() { result = classification }
+ }
+
+ /**
+ * A flow sink modeled by the `Cryptography` module.
+ */
+ class WeakPasswordHashingOperationInputSink extends Sink {
+ Cryptography::CryptographicAlgorithm algorithm;
+
+ WeakPasswordHashingOperationInputSink() {
+ exists(Cryptography::CryptographicOperation operation |
+ (
+ algorithm instanceof Cryptography::PasswordHashingAlgorithm and
+ algorithm.isWeak()
+ or
+ algorithm instanceof Cryptography::HashingAlgorithm // Note that HashingAlgorithm and PasswordHashingAlgorithm are disjoint
+ ) and
+ algorithm = operation.getAlgorithm() and
+ this = operation.getAnInput()
+ )
+ }
+
+ override string getAlgorithmName() { result = algorithm.getName() }
+
+ override predicate isComputationallyExpensive() {
+ algorithm instanceof Cryptography::PasswordHashingAlgorithm
+ }
+ }
+}
diff --git a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
new file mode 100644
index 000000000000..422cbb835141
--- /dev/null
+++ b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
@@ -0,0 +1,104 @@
+
+
+
+
+ Using a broken or weak cryptographic hash function can leave data
+ vulnerable, and should not be used in security related code.
+
+
+
+ A strong cryptographic hash function should be resistant to:
+
+
+ -
+ pre-image attacks: if you know a hash value
h(x),
+ you should not be able to easily find the input x.
+
+ -
+ collision attacks: if you know a hash value
h(x),
+ you should not be able to easily find a different input y
+ with the same hash value h(x) = h(y).
+
+
+
+ In cases with a limited input space, such as for passwords, the hash
+ function also needs to be computationally expensive to be resistant to
+ brute-force attacks. Passwords should also have an unique salt applied
+ before hashing, but that is not considered by this query.
+
+
+
+ As an example, both MD5 and SHA-1 are known to be vulnerable to collision attacks.
+
+
+
+ Since it's OK to use a weak cryptographic hash function in a non-security
+ context, this query only alerts when these are used to hash sensitive
+ data (such as passwords, certificates, usernames).
+
+
+
+ Use of broken or weak cryptographic algorithms that are not hashing algorithms, is
+ handled by the rb/weak-cryptographic-algorithm query.
+
+
+
+
+
+
+ Ensure that you use a strong, modern cryptographic hash function:
+
+
+
+ -
+ such as Argon2, scrypt, bcrypt, or PBKDF2 for passwords and other data with limited input space.
+
+ -
+ such as SHA-2, or SHA-3 in other cases.
+
+
+
+
+
+
+
+ The following example shows two functions for checking whether the hash
+ of a certificate matches a known value -- to prevent tampering.
+
+ The first function uses MD5 that is known to be vulnerable to collision attacks.
+
+ The second function uses SHA-256 that is a strong cryptographic hashing function.
+
+
+
+
+
+
+
+ The following example shows two functions for hashing passwords.
+
+ The first function uses SHA-256 to hash passwords. Although SHA-256 is a
+ strong cryptographic hash function, it is not suitable for password
+ hashing since it is not computationally expensive.
+
+
+
+
+
+
+ The second function uses Argon2 (through the argon2
+ gem), which is a strong password hashing algorithm (and
+ includes a per-password salt by default).
+
+
+
+
+
+
+
+ OWASP: Password Storage Cheat Sheet
+
+
+
diff --git a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
new file mode 100644
index 000000000000..bd46bd50a837
--- /dev/null
+++ b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
@@ -0,0 +1,114 @@
+/**
+ * @name Use of a broken or weak cryptographic hashing algorithm on sensitive data
+ * @description Using broken or weak cryptographic hashing algorithms can compromise security.
+ * @kind path-problem
+ * @problem.severity warning
+ * @security-severity 7.5
+ * @precision high
+ * @id go/weak-sensitive-data-hashing
+ * @tags security
+ * external/cwe/cwe-327
+ * external/cwe/cwe-328
+ * external/cwe/cwe-916
+ */
+
+import go
+import semmle.go.security.WeakSensitiveDataHashingCustomizations
+
+/**
+ * Provides a taint-tracking configuration for detecting use of a broken or weak
+ * cryptographic hash function on sensitive data, that does NOT require a
+ * computationally expensive hash function.
+ */
+module NormalHashFunctionFlow {
+ import NormalHashFunction
+
+ private module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
+
+ predicate isBarrierIn(DataFlow::Node node) {
+ // make sources barriers so that we only report the closest instance
+ isSource(node)
+ }
+
+ predicate isBarrierOut(DataFlow::Node node) {
+ // make sinks barriers so that we only report the closest instance
+ isSink(node)
+ }
+ }
+
+ import TaintTracking::Global
+}
+
+/**
+ * Provides a taint-tracking configuration for detecting use of a broken or weak
+ * cryptographic hashing algorithm on passwords.
+ *
+ * Passwords has stricter requirements on the hashing algorithm used (must be
+ * computationally expensive to prevent brute-force attacks).
+ */
+module ComputationallyExpensiveHashFunctionFlow {
+ import ComputationallyExpensiveHashFunction
+
+ private module Config implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
+
+ predicate isBarrierIn(DataFlow::Node node) {
+ // make sources barriers so that we only report the closest instance
+ isSource(node)
+ }
+
+ predicate isBarrierOut(DataFlow::Node node) {
+ // make sinks barriers so that we only report the closest instance
+ isSink(node)
+ }
+ }
+
+ import TaintTracking::Global
+}
+
+/**
+ * Global taint-tracking for detecting both variants of "use of a broken or weak
+ * cryptographic hashing algorithm on sensitive data" vulnerabilities. The two configurations are
+ * merged to generate a combined path graph.
+ */
+module WeakSensitiveDataHashingFlow =
+ DataFlow::MergePathGraph;
+
+import WeakSensitiveDataHashingFlow::PathGraph
+
+from
+ WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink,
+ string ending, string algorithmName, string classification
+where
+ NormalHashFunctionFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) and
+ algorithmName = sink.getNode().(NormalHashFunction::Sink).getAlgorithmName() and
+ classification = source.getNode().(NormalHashFunction::Source).getClassification() and
+ ending = "."
+ or
+ ComputationallyExpensiveHashFunctionFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) and
+ algorithmName = sink.getNode().(ComputationallyExpensiveHashFunction::Sink).getAlgorithmName() and
+ classification =
+ source.getNode().(ComputationallyExpensiveHashFunction::Source).getClassification() and
+ (
+ sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
+ ending = "."
+ or
+ not sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
+ ending =
+ " for " + classification +
+ " hashing, since it is not a computationally expensive hash function."
+ )
+select sink.getNode(), source, sink,
+ "$@ is used in a hashing algorithm (" + algorithmName + ") that is insecure" + ending,
+ source.getNode(), "Sensitive data (" + classification + ")"
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.expected b/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.expected
new file mode 100644
index 000000000000..301658e22cb8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.expected
@@ -0,0 +1,22 @@
+#select
+| hashing.go:20:8:20:22 | secretByteSlice | hashing.go:20:8:20:22 | secretByteSlice | hashing.go:20:8:20:22 | secretByteSlice | $@ is used in a hashing algorithm (MD5) that is insecure. | hashing.go:20:8:20:22 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:21:10:21:24 | secretByteSlice | hashing.go:21:10:21:24 | secretByteSlice | hashing.go:21:10:21:24 | secretByteSlice | $@ is used in a hashing algorithm (MD5) that is insecure. | hashing.go:21:10:21:24 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:22:20:22:31 | secretString | hashing.go:22:20:22:31 | secretString | hashing.go:22:20:22:31 | secretString | $@ is used in a hashing algorithm (MD5) that is insecure. | hashing.go:22:20:22:31 | secretString | Sensitive data (secret) |
+| hashing.go:23:10:23:24 | secretByteSlice | hashing.go:23:10:23:24 | secretByteSlice | hashing.go:23:10:23:24 | secretByteSlice | $@ is used in a hashing algorithm (MD5) that is insecure. | hashing.go:23:10:23:24 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:25:17:25:31 | secretByteSlice | hashing.go:25:17:25:31 | secretByteSlice | hashing.go:25:17:25:31 | secretByteSlice | $@ is used in a hashing algorithm (SHA1) that is insecure. | hashing.go:25:17:25:31 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:26:11:26:25 | secretByteSlice | hashing.go:26:11:26:25 | secretByteSlice | hashing.go:26:11:26:25 | secretByteSlice | $@ is used in a hashing algorithm (SHA1) that is insecure. | hashing.go:26:11:26:25 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:28:16:28:30 | secretByteSlice | hashing.go:28:16:28:30 | secretByteSlice | hashing.go:28:16:28:30 | secretByteSlice | $@ is used in a hashing algorithm (MD4) that is insecure. | hashing.go:28:16:28:30 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:29:22:29:36 | secretByteSlice | hashing.go:29:22:29:36 | secretByteSlice | hashing.go:29:22:29:36 | secretByteSlice | $@ is used in a hashing algorithm (RIPEMD160) that is insecure. | hashing.go:29:22:29:36 | secretByteSlice | Sensitive data (secret) |
+| hashing.go:80:16:80:23 | password | hashing.go:80:16:80:23 | password | hashing.go:80:16:80:23 | password | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | hashing.go:80:16:80:23 | password | Sensitive data (password) |
+edges
+nodes
+| hashing.go:20:8:20:22 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:21:10:21:24 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:22:20:22:31 | secretString | semmle.label | secretString |
+| hashing.go:23:10:23:24 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:25:17:25:31 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:26:11:26:25 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:28:16:28:30 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:29:22:29:36 | secretByteSlice | semmle.label | secretByteSlice |
+| hashing.go:80:16:80:23 | password | semmle.label | password |
+subpaths
diff --git a/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.qlref b/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.qlref
new file mode 100644
index 000000000000..ec9ae0993a26
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/WeakSensitiveDataHashing.qlref
@@ -0,0 +1,4 @@
+query: Security/CWE-327/WeakSensitiveDataHashing.ql
+postprocess:
+ - utils/test/PrettyPrintModels.ql
+ - utils/test/InlineExpectationsTestQuery.ql
diff --git a/go/ql/test/query-tests/Security/CWE-327/go.mod b/go/ql/test/query-tests/Security/CWE-327/go.mod
index bf42b84feefd..59c69723ef55 100644
--- a/go/ql/test/query-tests/Security/CWE-327/go.mod
+++ b/go/ql/test/query-tests/Security/CWE-327/go.mod
@@ -1,3 +1,5 @@
module test
-go 1.24
+go 1.24.0
+
+require golang.org/x/crypto v0.43.0
diff --git a/go/ql/test/query-tests/Security/CWE-327/hashing.go b/go/ql/test/query-tests/Security/CWE-327/hashing.go
new file mode 100644
index 000000000000..4943da353846
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/hashing.go
@@ -0,0 +1,81 @@
+package main
+
+//go:generate depstubber -vendor golang.org/x/crypto/md4 "" New
+//go:generate depstubber -vendor golang.org/x/crypto/ripemd160 "" New
+
+import (
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha3"
+ "crypto/sha512"
+ "io"
+
+ "golang.org/x/crypto/md4"
+ "golang.org/x/crypto/ripemd160"
+)
+
+func WeakHashes() {
+ h := md5.New()
+ h.Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="MD5. init from line 19."
+ h.Write(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="MD5. init from line 19."
+ io.WriteString(h, secretString) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="MD5. init from line 19."
+ md5.Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="MD5. init from line 23."
+
+ sha1.New().Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="SHA1. init from line 25."
+ sha1.Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="SHA1. init from line 26."
+
+ md4.New().Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="MD4. init from line 28."
+ ripemd160.New().Sum(secretByteSlice) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="RIPEMD160. init from line 29."
+
+ // Only alert when sensitive data is hashed.
+ md5.New().Sum(public) // $ CryptographicOperation="MD5. init from line 32."
+ md5.Sum(public) // $ CryptographicOperation="MD5. init from line 33."
+ sha1.New().Sum(public) // $ CryptographicOperation="SHA1. init from line 34."
+ sha1.Sum(public) // $ CryptographicOperation="SHA1. init from line 35."
+}
+
+func StrongHashes() {
+ sha256.New224().Sum(secretByteSlice) // $ CryptographicOperation="SHA224. init from line 39."
+ sha256.Sum224(secretByteSlice) // $ CryptographicOperation="SHA224. init from line 40."
+
+ sha256.New().Sum(secretByteSlice) // $ CryptographicOperation="SHA256. init from line 42."
+ sha256.Sum256(secretByteSlice) // $ CryptographicOperation="SHA256. init from line 43."
+
+ sha512.New().Sum(secretByteSlice) // $ CryptographicOperation="SHA512. init from line 45."
+ sha512.Sum512(secretByteSlice) // $ CryptographicOperation="SHA512. init from line 46."
+
+ sha512.New384().Sum(secretByteSlice) // $ CryptographicOperation="SHA384. init from line 48."
+ sha512.Sum384(secretByteSlice) // $ CryptographicOperation="SHA384. init from line 49."
+
+ sha512.New512_224().Sum(secretByteSlice) // $ CryptographicOperation="SHA512224. init from line 51."
+ sha512.Sum512_224(secretByteSlice) // $ CryptographicOperation="SHA512224. init from line 52."
+
+ sha512.New512_256().Sum(secretByteSlice) // $ CryptographicOperation="SHA512256. init from line 54."
+ sha512.Sum512_256(secretByteSlice) // $ CryptographicOperation="SHA512256. init from line 55."
+
+ sha3.New224().Sum(secretByteSlice) // $ CryptographicOperation="SHA3224. init from line 57."
+ sha3.Sum224(secretByteSlice) // $ CryptographicOperation="SHA3224. init from line 58."
+
+ sha3.New256().Sum(secretByteSlice) // $ CryptographicOperation="SHA3256. init from line 60."
+ sha3.Sum256(secretByteSlice) // $ CryptographicOperation="SHA3256. init from line 61."
+
+ sha3.New384().Sum(secretByteSlice) // $ CryptographicOperation="SHA3384. init from line 63."
+ sha3.Sum384(secretByteSlice) // $ CryptographicOperation="SHA3384. init from line 64."
+
+ sha3.New512().Sum(secretByteSlice) // $ CryptographicOperation="SHA3512. init from line 66."
+ sha3.Sum512(secretByteSlice) // $ CryptographicOperation="SHA3512. init from line 67."
+
+ sha3.NewSHAKE128().Write(secretByteSlice) // $ CryptographicOperation="SHAKE128. init from line 69."
+ sha3.NewCSHAKE128(nil, nil).Write(secretByteSlice) // $ CryptographicOperation="SHAKE128. init from line 70."
+ sha3.SumSHAKE128(secretByteSlice, 100) // $ CryptographicOperation="SHAKE128. init from line 71."
+
+ sha3.NewSHAKE256().Write(secretByteSlice) // $ CryptographicOperation="SHAKE256. init from line 73."
+ sha3.NewCSHAKE256(nil, nil).Write(secretByteSlice) // $ CryptographicOperation="SHAKE256. init from line 74."
+ sha3.SumSHAKE256(secretByteSlice, 100) // $ CryptographicOperation="SHAKE256. init from line 75."
+}
+
+func PasswordHashing() {
+ password := []byte("")
+ sha256.Sum256(password) // $ Alert[go/weak-sensitive-data-hashing] CryptographicOperation="SHA256. init from line 80."
+}
diff --git a/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/md4/stub.go b/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/md4/stub.go
new file mode 100644
index 000000000000..777cc50c0c1c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/md4/stub.go
@@ -0,0 +1,16 @@
+// Code generated by depstubber. DO NOT EDIT.
+// This is a simple stub for golang.org/x/crypto/md4, strictly for use in testing.
+
+// See the LICENSE file for information about the licensing of the original library.
+// Source: golang.org/x/crypto/md4 (exports: ; functions: New)
+
+// Package md4 is a stub of golang.org/x/crypto/md4, generated by depstubber.
+package md4
+
+import (
+ hash "hash"
+)
+
+func New() hash.Hash {
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/ripemd160/stub.go b/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/ripemd160/stub.go
new file mode 100644
index 000000000000..995d3339d8cd
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/vendor/golang.org/x/crypto/ripemd160/stub.go
@@ -0,0 +1,16 @@
+// Code generated by depstubber. DO NOT EDIT.
+// This is a simple stub for golang.org/x/crypto/ripemd160, strictly for use in testing.
+
+// See the LICENSE file for information about the licensing of the original library.
+// Source: golang.org/x/crypto/ripemd160 (exports: ; functions: New)
+
+// Package ripemd160 is a stub of golang.org/x/crypto/ripemd160, generated by depstubber.
+package ripemd160
+
+import (
+ hash "hash"
+)
+
+func New() hash.Hash {
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-327/vendor/modules.txt b/go/ql/test/query-tests/Security/CWE-327/vendor/modules.txt
new file mode 100644
index 000000000000..1927762821ca
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-327/vendor/modules.txt
@@ -0,0 +1,4 @@
+# golang.org/x/crypto v0.43.0
+## explicit
+golang.org/x/crypto/md4
+golang.org/x/crypto/ripemd160
From ac3920c53e7c5c4162572543c4a0257e016a0e64 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 21 Oct 2025 16:15:43 +0100
Subject: [PATCH 11/18] Add change note
---
.../src/change-notes/2025-10-21-go-weak-crypto-algorithm.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 go/ql/src/change-notes/2025-10-21-go-weak-crypto-algorithm.md
diff --git a/go/ql/src/change-notes/2025-10-21-go-weak-crypto-algorithm.md b/go/ql/src/change-notes/2025-10-21-go-weak-crypto-algorithm.md
new file mode 100644
index 000000000000..d5f9a08fb7f8
--- /dev/null
+++ b/go/ql/src/change-notes/2025-10-21-go-weak-crypto-algorithm.md
@@ -0,0 +1,5 @@
+---
+category: newQuery
+---
+* Added a new query, `go/weak-crypto-algorithm`, to detect the use of a broken or weak cryptographic algorithm. A very simple version of this query was originally contributed as an [experimental query by @dilanbhalla](https://github.com/github/codeql-go/pull/284).
+* Added a new query, `go/weak-sensitive-data-hashing`, to detect the use of a broken or weak cryptographic hash algorithm on sensitive data.
From 42bd86b58120ce133e4c977ed911e2aae5de6192 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 21 Oct 2025 21:28:19 +0100
Subject: [PATCH 12/18] Fix failing ruby crypto test that lists all algorithms
---
ruby/ql/test/library-tests/security/CryptoAlgorithms.expected | 2 ++
1 file changed, 2 insertions(+)
diff --git a/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected b/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected
index eedddb2df9ff..3f1ba8e12c67 100644
--- a/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected
+++ b/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected
@@ -34,6 +34,8 @@ strongHashingAlgorithms
| SHA3256 |
| SHA3384 |
| SHA3512 |
+| SHA512224 |
+| SHA512256 |
| SHAKE128 |
| SHAKE256 |
| SM3 |
From 7aa1d17023f7bfa49ae035830a320cd30ad671b8 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 21 Oct 2025 21:59:46 +0100
Subject: [PATCH 13/18] Fix query suite integration tests
---
.../integration-tests/query-suite/go-code-scanning.qls.expected | 2 ++
.../query-suite/go-security-and-quality.qls.expected | 2 ++
.../query-suite/go-security-extended.qls.expected | 2 ++
.../integration-tests/query-suite/not_included_in_qls.expected | 1 -
4 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/go/ql/integration-tests/query-suite/go-code-scanning.qls.expected b/go/ql/integration-tests/query-suite/go-code-scanning.qls.expected
index 20fcacbc3896..d8d3e0a13e75 100644
--- a/go/ql/integration-tests/query-suite/go-code-scanning.qls.expected
+++ b/go/ql/integration-tests/query-suite/go-code-scanning.qls.expected
@@ -18,7 +18,9 @@ ql/go/ql/src/Security/CWE-295/DisabledCertificateCheck.ql
ql/go/ql/src/Security/CWE-312/CleartextLogging.ql
ql/go/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql
ql/go/ql/src/Security/CWE-326/InsufficientKeySize.ql
+ql/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
ql/go/ql/src/Security/CWE-327/InsecureTLS.ql
+ql/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
ql/go/ql/src/Security/CWE-338/InsecureRandomness.ql
ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
diff --git a/go/ql/integration-tests/query-suite/go-security-and-quality.qls.expected b/go/ql/integration-tests/query-suite/go-security-and-quality.qls.expected
index ee0ec8f42ba7..71bcb2b03300 100644
--- a/go/ql/integration-tests/query-suite/go-security-and-quality.qls.expected
+++ b/go/ql/integration-tests/query-suite/go-security-and-quality.qls.expected
@@ -41,7 +41,9 @@ ql/go/ql/src/Security/CWE-295/DisabledCertificateCheck.ql
ql/go/ql/src/Security/CWE-312/CleartextLogging.ql
ql/go/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql
ql/go/ql/src/Security/CWE-326/InsufficientKeySize.ql
+ql/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
ql/go/ql/src/Security/CWE-327/InsecureTLS.ql
+ql/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
ql/go/ql/src/Security/CWE-338/InsecureRandomness.ql
ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
diff --git a/go/ql/integration-tests/query-suite/go-security-extended.qls.expected b/go/ql/integration-tests/query-suite/go-security-extended.qls.expected
index 9116f7b7ebf6..b0447a6c3eb3 100644
--- a/go/ql/integration-tests/query-suite/go-security-extended.qls.expected
+++ b/go/ql/integration-tests/query-suite/go-security-extended.qls.expected
@@ -19,7 +19,9 @@ ql/go/ql/src/Security/CWE-295/DisabledCertificateCheck.ql
ql/go/ql/src/Security/CWE-312/CleartextLogging.ql
ql/go/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql
ql/go/ql/src/Security/CWE-326/InsufficientKeySize.ql
+ql/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql
ql/go/ql/src/Security/CWE-327/InsecureTLS.ql
+ql/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
ql/go/ql/src/Security/CWE-338/InsecureRandomness.ql
ql/go/ql/src/Security/CWE-347/MissingJwtSignatureCheck.ql
ql/go/ql/src/Security/CWE-352/ConstantOauth2State.ql
diff --git a/go/ql/integration-tests/query-suite/not_included_in_qls.expected b/go/ql/integration-tests/query-suite/not_included_in_qls.expected
index 3b79e47da44f..7b8b86a7a533 100644
--- a/go/ql/integration-tests/query-suite/not_included_in_qls.expected
+++ b/go/ql/integration-tests/query-suite/not_included_in_qls.expected
@@ -14,7 +14,6 @@ ql/go/ql/src/experimental/CWE-203/Timing.ql
ql/go/ql/src/experimental/CWE-285/PamAuthBypass.ql
ql/go/ql/src/experimental/CWE-287/ImproperLdapAuth.ql
ql/go/ql/src/experimental/CWE-321-V2/HardCodedKeys.ql
-ql/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithm.ql
ql/go/ql/src/experimental/CWE-369/DivideByZero.ql
ql/go/ql/src/experimental/CWE-400/DatabaseCallInLoop.ql
ql/go/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
From 867ee66d1516e616fd9bb7688619491b2e928f1b Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 31 Oct 2025 16:06:24 +0000
Subject: [PATCH 14/18] Fix capitalization of class names
---
.../semmle/go/frameworks/CryptoLibraries.qll | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
index 0c56d8c7e6a5..6fe299c39ed4 100644
--- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
+++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
@@ -109,9 +109,9 @@ private module Crypto {
}
private module Rc4 {
- private class CipherXORKeyStream extends CryptographicOperation::Range instanceof DataFlow::CallNode
+ private class CipherXorKeyStream extends CryptographicOperation::Range instanceof DataFlow::CallNode
{
- CipherXORKeyStream() {
+ CipherXorKeyStream() {
this.(DataFlow::MethodCallNode)
.getTarget()
.hasQualifiedName("crypto/rc4", "Cipher", "XORKeyStream")
@@ -312,26 +312,26 @@ private module Crypto {
}
private module Cipher {
- private class NewCBCEncrypter extends StdLibNewEncrypter {
- NewCBCEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCBCEncrypter") }
+ private class NewCbcEncrypter extends StdLibNewEncrypter {
+ NewCbcEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCBCEncrypter") }
override BlockMode getMode() { result = "CBC" }
}
- private class NewCFBEncrypter extends StdLibNewEncrypter {
- NewCFBEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCFBEncrypter") }
+ private class NewCfbEncrypter extends StdLibNewEncrypter {
+ NewCfbEncrypter() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCFBEncrypter") }
override BlockMode getMode() { result = "CFB" }
}
- private class NewCTR extends StdLibNewEncrypter {
- NewCTR() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCTR") }
+ private class NewCtr extends StdLibNewEncrypter {
+ NewCtr() { this.getTarget().hasQualifiedName("crypto/cipher", "NewCTR") }
override BlockMode getMode() { result = "CTR" }
}
- private class NewGCM extends StdLibNewEncrypter {
- NewGCM() {
+ private class NewGcm extends StdLibNewEncrypter {
+ NewGcm() {
exists(string name | this.getTarget().hasQualifiedName("crypto/cipher", name) |
name = ["NewGCM", "NewGCMWithNonceSize", "NewGCMWithRandomNonce", "NewGCMWithTagSize"]
)
@@ -340,8 +340,8 @@ private module Crypto {
override BlockMode getMode() { result = "GCM" }
}
- private class NewOFB extends StdLibNewEncrypter {
- NewOFB() { this.getTarget().hasQualifiedName("crypto/cipher", "NewOFB") }
+ private class NewOfb extends StdLibNewEncrypter {
+ NewOfb() { this.getTarget().hasQualifiedName("crypto/cipher", "NewOFB") }
override BlockMode getMode() { result = "OFB" }
}
@@ -373,8 +373,8 @@ private module Crypto {
}
}
- private class StreamXORKeyStream extends EncryptionMethodCall {
- StreamXORKeyStream() {
+ private class StreamXorKeyStream extends EncryptionMethodCall {
+ StreamXorKeyStream() {
this.(DataFlow::MethodCallNode)
.getTarget()
.hasQualifiedName("crypto/cipher", "Stream", "XORKeyStream") and
From 55ef5416deb6b0f95482ba60cbcce651b963621e Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Mon, 3 Nov 2025 13:23:11 +0000
Subject: [PATCH 15/18] Add query help examples
---
.../CWE-327/BrokenCryptoAlgorithm.qhelp | 8 +--
.../CWE-327/WeakSensitiveDataHashing.qhelp | 21 +++----
go/ql/src/Security/CWE-327/examples/Crypto.go | 55 ++++---------------
.../CWE-327/examples/WeakPasswordHashing.go | 21 +++++++
.../CWE-327/examples/WeakSecretHashing.go | 19 +++++++
5 files changed, 62 insertions(+), 62 deletions(-)
create mode 100644 go/ql/src/Security/CWE-327/examples/WeakPasswordHashing.go
create mode 100644 go/ql/src/Security/CWE-327/examples/WeakSecretHashing.go
diff --git a/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp
index 0283e142fbad..a65af78c0aec 100644
--- a/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp
+++ b/go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp
@@ -28,10 +28,10 @@
- The following code uses the different packages to encrypt/hash
- some secret data. The first few examples uses DES, MD5, RC4, and SHA1,
- which are older algorithms that are now considered weak. The following
- examples use AES and SHA256, which are stronger, more modern algorithms.
+ The following code uses the different packages to encrypt
+ some secret data. The first example uses DES,
+ which is an older algorithm that is now considered weak. The following
+ example uses AES, which is a stronger, more modern algorithm.
diff --git a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
index 422cbb835141..1fa64e4adaf2 100644
--- a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
+++ b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelp
@@ -65,35 +65,28 @@
The following example shows two functions for checking whether the hash
- of a certificate matches a known value -- to prevent tampering.
+ of a secret matches a known value.
- The first function uses MD5 that is known to be vulnerable to collision attacks.
+ The first function uses SHA-1 that is known to be vulnerable to collision attacks.
The second function uses SHA-256 that is a strong cryptographic hashing function.
-
+
The following example shows two functions for hashing passwords.
- The first function uses SHA-256 to hash passwords. Although SHA-256 is a
- strong cryptographic hash function, it is not suitable for password
+ The first example uses SHA-256 to hash passwords. Although
+ SHA-256 is a strong cryptographic hash function, it is not suitable for password
hashing since it is not computationally expensive.
-
-
-
-
-
- The second function uses Argon2 (through the argon2
- gem), which is a strong password hashing algorithm (and
- includes a per-password salt by default).
+ The second function uses PBKDF2, which is a strong password hashing algorithm.
-
+
diff --git a/go/ql/src/Security/CWE-327/examples/Crypto.go b/go/ql/src/Security/CWE-327/examples/Crypto.go
index bc2b2fdeba44..b3f71f0772bc 100644
--- a/go/ql/src/Security/CWE-327/examples/Crypto.go
+++ b/go/ql/src/Security/CWE-327/examples/Crypto.go
@@ -3,51 +3,18 @@ package main
import (
"crypto/aes"
"crypto/des"
- "crypto/md5"
- "crypto/rc4"
- "crypto/sha1"
- "crypto/sha256"
)
-func main() {
- public := []byte("hello")
-
- password := []byte("123456")
- buf := password // testing dataflow by passing into different variable
-
- // BAD, des is a weak crypto algorithm and password is sensitive data
- des.NewTripleDESCipher(buf)
-
- // BAD, md5 is a weak crypto algorithm and password is sensitive data
- md5.Sum(buf)
-
- // BAD, rc4 is a weak crypto algorithm and password is sensitive data
- rc4.NewCipher(buf)
-
- // BAD, sha1 is a weak crypto algorithm and password is sensitive data
- sha1.Sum(buf)
-
- // GOOD, password is sensitive data but aes is a strong crypto algorithm
- aes.NewCipher(buf)
-
- // GOOD, password is sensitive data but sha256 is a strong crypto algorithm
- sha256.Sum256(buf)
-
- // GOOD, des is a weak crypto algorithm but public is not sensitive data
- des.NewTripleDESCipher(public)
-
- // GOOD, md5 is a weak crypto algorithm but public is not sensitive data
- md5.Sum(public)
-
- // GOOD, rc4 is a weak crypto algorithm but public is not sensitive data
- rc4.NewCipher(public)
-
- // GOOD, sha1 is a weak crypto algorithm but public is not sensitive data
- sha1.Sum(public)
-
- // GOOD, aes is a strong crypto algorithm and public is not sensitive data
- aes.NewCipher(public)
+func EncryptMessageWeak(key []byte, message []byte) (dst []byte) {
+ // BAD, DES is a weak crypto algorithm
+ block, _ := des.NewCipher(key)
+ block.Encrypt(dst, message)
+ return
+}
- // GOOD, sha256 is a strong crypto algorithm and public is not sensitive data
- sha256.Sum256(public)
+func EncryptMessageStrong(key []byte, message []byte) (dst []byte) {
+ // GOOD, AES is a weak crypto algorithm
+ block, _ := aes.NewCipher(key)
+ block.Encrypt(dst, message)
+ return
}
diff --git a/go/ql/src/Security/CWE-327/examples/WeakPasswordHashing.go b/go/ql/src/Security/CWE-327/examples/WeakPasswordHashing.go
new file mode 100644
index 000000000000..671edede7d36
--- /dev/null
+++ b/go/ql/src/Security/CWE-327/examples/WeakPasswordHashing.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "crypto/pbkdf2"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+)
+
+func GetPasswordHashBad(password string) [32]byte {
+ // BAD, SHA256 is a strong hashing algorithm but it is not computationally expensive
+ return sha256.Sum256([]byte(password))
+}
+
+func GetPasswordHashGood(password string) []byte {
+ // GOOD, PBKDF2 is a strong hashing algorithm and it is computationally expensive
+ salt := make([]byte, 16)
+ rand.Read(salt)
+ key, _ := pbkdf2.Key(sha512.New, password, salt, 4096, 32)
+ return key
+}
diff --git a/go/ql/src/Security/CWE-327/examples/WeakSecretHashing.go b/go/ql/src/Security/CWE-327/examples/WeakSecretHashing.go
new file mode 100644
index 000000000000..fd65b802548b
--- /dev/null
+++ b/go/ql/src/Security/CWE-327/examples/WeakSecretHashing.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "crypto/sha1"
+ "crypto/sha256"
+ "slices"
+)
+
+func SecretMatchesKnownHashBad(secret []byte, known_hash []byte) bool {
+ // BAD, SHA1 is a weak crypto algorithm and secret is sensitive data
+ h := sha1.New()
+ return slices.Equal(h.Sum(secret), known_hash)
+}
+
+func SecretMatchesKnownHashGood(secret []byte, known_hash []byte) bool {
+ // GOOD, SHA256 is a strong hashing algorithm
+ h := sha256.New()
+ return slices.Equal(h.Sum(secret), known_hash)
+}
From 416baf60bab31a037939f136665127de6165c6c6 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Mon, 3 Nov 2025 13:23:43 +0000
Subject: [PATCH 16/18] Fix small mistake in Ruby query help
---
.../src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelp b/ruby/ql/src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelp
index 422cbb835141..33d0c845a66d 100644
--- a/ruby/ql/src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelp
+++ b/ruby/ql/src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelp
@@ -67,7 +67,7 @@
The following example shows two functions for checking whether the hash
of a certificate matches a known value -- to prevent tampering.
- The first function uses MD5 that is known to be vulnerable to collision attacks.
+ The first function uses SHA-1 that is known to be vulnerable to collision attacks.
The second function uses SHA-256 that is a strong cryptographic hashing function.
From d2cd96ef7b035fd78f05bfb5d4f7e4999f5a78ef Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Mon, 3 Nov 2025 17:20:19 +0000
Subject: [PATCH 17/18] Fix diff-informed predicates
---
go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll | 4 ----
go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql | 4 ++++
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
index 6fe299c39ed4..154ac82e7a2a 100644
--- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
+++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll
@@ -21,8 +21,6 @@ private module HashConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof HashAlgorithmInit }
predicate isSink(DataFlow::Node sink) { any() }
-
- predicate observeDiffInformedIncrementalMode() { any() }
}
/** Tracks the flow of hash algorithms. */
@@ -50,8 +48,6 @@ private module EncryptionConfig implements DataFlow::ConfigSig {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(BlockModeInit nbcm).step(node1, node2)
}
-
- predicate observeDiffInformedIncrementalMode() { any() }
}
/**
diff --git a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
index bd46bd50a837..0a38d9729f01 100644
--- a/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
+++ b/go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql
@@ -39,6 +39,8 @@ module NormalHashFunctionFlow {
// make sinks barriers so that we only report the closest instance
isSink(node)
}
+
+ predicate observeDiffInformedIncrementalMode() { any() }
}
import TaintTracking::Global
@@ -70,6 +72,8 @@ module ComputationallyExpensiveHashFunctionFlow {
// make sinks barriers so that we only report the closest instance
isSink(node)
}
+
+ predicate observeDiffInformedIncrementalMode() { any() }
}
import TaintTracking::Global
From 0d77b8c77bb2836365f46bbd30476be7a73d51cd Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 4 Nov 2025 10:33:04 +0000
Subject: [PATCH 18/18] Remove unnecessary import
---
.../go/security/WeakSensitiveDataHashingCustomizations.qll | 1 -
1 file changed, 1 deletion(-)
diff --git a/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll b/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
index f03b93eb7c2e..4893193ef4fe 100644
--- a/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
+++ b/go/ql/lib/semmle/go/security/WeakSensitiveDataHashingCustomizations.qll
@@ -9,7 +9,6 @@
*/
import go
-import semmle.go.dataflow.internal.DataFlowPrivate
private import semmle.go.security.SensitiveActions
/**