- Notifications
You must be signed in to change notification settings - Fork 1.8k
Go: promote go/weak-crypto-algorithm #20666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR promotes the go/weak-crypto-algorithm query from experimental to standard by implementing comprehensive modeling of cryptographic operations in Go. The query now detects when sensitive data is used with broken or weak cryptographic algorithms (DES, 3DES, RC4, MD5, SHA1) across various crypto libraries and block cipher modes.
Key changes:
- Completely rewrote cryptographic operation modeling using the shared Concepts library
- Added support for block cipher modes (CBC, CTR, CFB, OFB, GCM) and stream operations
- Extended coverage to include hash operations with proper initialization tracking
- Added comprehensive test cases covering multiple encryption and hashing scenarios
Reviewed Changes
Copilot reviewed 20 out of 23 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql | New production query file that replaces the experimental query |
| go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll | New taint-tracking configuration for the query |
| go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmCustomizations.qll | New customizations defining sources, sinks, and sanitizers |
| go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll | Comprehensive modeling of Go crypto libraries with algorithm and block mode tracking |
| go/ql/lib/semmle/go/Concepts.qll | Added cryptography concepts including algorithm types and operation abstractions |
| go/ql/lib/qlpack.yml | Added dependency on codeql/concepts shared library |
| go/ql/lib/go.qll | Imported CryptoLibraries framework |
| shared/concepts/codeql/concepts/internal/CryptoAlgorithmNames.qll | Added SHA512224 and SHA512256 to strong hashing algorithms |
| go/ql/test/query-tests/Security/CWE-327/Crypto.go | Comprehensive test cases for various cryptographic operations |
| go/ql/src/experimental/CWE-327/* | Removed old experimental query files |
| go/ql/test/query-tests/Security/CWE-327/CryptoAlgorithm.ql | New test helper for validating CryptographicOperation modeling |
| go/ql/src/change-notes/2025-10-21-go-weak-crypto-algorithm.md | Change note documenting the new query |
| QHelp previews: go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelpUse of a broken or weak cryptographic algorithmUsing weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker. Many cryptographic algorithms provided by cryptography libraries are known to be weak. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be. RecommendationEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing. ExampleThe 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. package main import ( "crypto/aes" "crypto/des" ) func EncryptMessageWeak(key []byte, message []byte) (dst []byte) { // BAD, DES is a weak crypto algorithm block, _ := des.NewCipher(key) block.Encrypt(dst, message) return } func EncryptMessageStrong(key []byte, message []byte) (dst []byte) { // GOOD, AES is a weak crypto algorithm block, _ := aes.NewCipher(key) block.Encrypt(dst, message) return }References
go/ql/src/Security/CWE-327/WeakSensitiveDataHashing.qhelpUse of a broken or weak cryptographic hashing algorithm on sensitive dataUsing 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:
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 RecommendationEnsure that you use a strong, modern cryptographic hash function:
ExampleThe following example shows two functions for checking whether the hash of a secret matches a known value. 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. 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) }ExampleThe following example shows two functions for hashing passwords. 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 PBKDF2, which is a strong password hashing algorithm. 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 }References
ruby/ql/src/queries/security/cwe-327/WeakSensitiveDataHashing.qhelpUse of a broken or weak cryptographic hashing algorithm on sensitive dataUsing 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:
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 RecommendationEnsure that you use a strong, modern cryptographic hash function:
ExampleThe following example shows two functions for checking whether the hash of a certificate matches a known value -- to prevent tampering. 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. require 'openssl' def certificate_matches_known_hash_bad(certificate, known_hash) hash = OpenSSL::Digest.new('SHA1').digest certificate hash == known_hash end def certificate_matches_known_hash_good(certificate, known_hash) hash = OpenSSL::Digest.new('SHA256').digest certificate hash == known_hash endExampleThe 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. require 'openssl' def get_password_hash(password, salt) OpenSSL::Digest.new('SHA256').digest(password + salt) # BAD endThe second function uses Argon2 (through the require 'argon2' def get_initial_hash(password) Argon2::Password.create(password) end def check_password(password, known_hash) Argon2::Password.verify_password(password, known_hash) endReferences
|
| Location getASelectedSinkLocation(DataFlow::Node sink) { | ||
| result = sink.(Sink).getLocation() | ||
| or | ||
| result = sink.(Sink).getInitialization().getLocation() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query at go/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql only selects source and sink, not getInitialization(). Try removing this location override (getASelectedSinkLocation) altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. This has highlighted some differences from the existing queries for other languages which I wasn't aware of. I'll need to update the PR quite a lot, so I'm putting it back in draft now.
d231a17 to 9e04cf3 Compare | 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 |
Check warning
Code scanning / CodeQL
Consistent alert message Warning
f0e340c to d2cd96e Compare | Results from running MRVA on 1000 go repos:
|
| I ran a one-branch DCA experiment for these two queries on all the repos from MRVA that had results for them. It didn't show anything interesting, like bad join orders. |
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.