From 5abc596162e5f1fa6fbb7c1386df0da36d7f74a1 Mon Sep 17 00:00:00 2001 From: Chanel Young Date: Thu, 9 Apr 2026 09:26:23 -0700 Subject: [PATCH 1/3] Add weak HMAC algorithm detection query for PowerShell Detects HMACMD5, HMACSHA1, and HMACRIPEMD160 usage via New-Object, static Create(), and ::new() patterns. Covers: Cryptography.10020 (CWE-327, CWE-328) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/queries/security/cwe-328/WeakHmac.ql | 92 +++++++++++++++++++ .../cwe-328/WeakHmac/WeakHmac.expected | 4 + .../security/cwe-328/WeakHmac/WeakHmac.qlref | 1 + .../security/cwe-328/WeakHmac/test.ps1 | 28 ++++++ 4 files changed, 125 insertions(+) create mode 100644 powershell/ql/src/queries/security/cwe-328/WeakHmac.ql create mode 100644 powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected create mode 100644 powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref create mode 100644 powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 diff --git a/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql b/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql new file mode 100644 index 000000000000..03147d219d04 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql @@ -0,0 +1,92 @@ +/** + * @name Use of weak HMAC algorithm + * @description Using weak HMAC algorithms like HMACMD5 or HMACSHA1 can compromise message authentication. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id powershell/microsoft/security/weak-hmac + * @tags security + * external/cwe/cwe-327 + * external/cwe/cwe-328 + */ + +import powershell +import semmle.code.powershell.ApiGraphs +import semmle.code.powershell.dataflow.DataFlow +import semmle.code.powershell.security.cryptography.CryptographyModule + +/** + * Holds if `name` is a weak HMAC algorithm name (lowercase). + */ +predicate isWeakHmacAlgorithm(string name) { + name = ["hmacmd5", "hmacsha1", "hmacripemd160"] +} + +/** A weak HMAC algorithm instantiated via New-Object. */ +class WeakHmacObjectCreation extends DataFlow::ObjectCreationNode { + string algName; + + WeakHmacObjectCreation() { + exists(string objName | + objName = + this.getExprNode().getExpr().(CallExpr).getAnArgument().getValue().asString().toLowerCase() and + ( + objName = "system.security.cryptography." + algName or + objName = algName + ) and + isWeakHmacAlgorithm(algName) + ) + } + + string getName() { result = algName } +} + +/** A weak HMAC algorithm instantiated via [Type]::Create() or [Type]::new(). */ +class WeakHmacCreateCall extends DataFlow::CallNode { + string algName; + + WeakHmacCreateCall() { + isWeakHmacAlgorithm(algName) and + ( + this = + API::getTopLevelMember("system") + .getMember("security") + .getMember("cryptography") + .getMember(algName) + .getMember("create") + .asCall() + or + this = + API::getTopLevelMember("system") + .getMember("security") + .getMember("cryptography") + .getMember(algName) + .getMember("new") + .asCall() + ) + } + + string getName() { result = algName } +} + +/** A weak HMAC algorithm passed as string to CryptoConfig.CreateFromName(). */ +class WeakHmacCreateFromNameCall extends CryptoAlgorithmCreateFromNameCall { + string algName; + + WeakHmacCreateFromNameCall() { + objectName = ["", "system.security.cryptography."] + algName and + isWeakHmacAlgorithm(algName) + } + + string getHmacName() { result = algName } +} + +from DataFlow::Node node, string algName +where + exists(WeakHmacObjectCreation c | node = c and algName = c.getName()) + or + exists(WeakHmacCreateCall c | node = c and algName = c.getName()) + or + exists(WeakHmacCreateFromNameCall c | node = c and algName = c.getHmacName()) +select node, "Use of weak HMAC algorithm: " + algName + ". Use HMACSHA256 or stronger." diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected new file mode 100644 index 000000000000..a96f5b0fee52 --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected @@ -0,0 +1,4 @@ +| test.ps1:6:9:6:55 | Call to new-object | Use of weak HMAC algorithm: hmacmd5. Use HMACSHA256 or stronger. | +| test.ps1:9:9:9:56 | Call to new-object | Use of weak HMAC algorithm: hmacsha1. Use HMACSHA256 or stronger. | +| test.ps1:12:9:12:56 | Call to create | Use of weak HMAC algorithm: hmacmd5. Use HMACSHA256 or stronger. | +| test.ps1:15:9:15:54 | Call to new | Use of weak HMAC algorithm: hmacsha1. Use HMACSHA256 or stronger. | diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref new file mode 100644 index 000000000000..c226f3332796 --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref @@ -0,0 +1 @@ +queries/security/cwe-328/WeakHmac.ql diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 new file mode 100644 index 000000000000..a07d3b9b05ba --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 @@ -0,0 +1,28 @@ +# =================================================================== +# ========== TRUE POSITIVES (should trigger alert) ================== +# =================================================================== + +# --- Case 1: HMACMD5 via New-Object --- +$hmac = New-Object System.Security.Cryptography.HMACMD5 # BAD + +# --- Case 2: HMACSHA1 via New-Object --- +$hmac = New-Object System.Security.Cryptography.HMACSHA1 # BAD + +# --- Case 3: HMACMD5 via static Create --- +$hmac = [System.Security.Cryptography.HMACMD5]::Create() # BAD + +# --- Case 4: HMACSHA1 via ::new() --- +$hmac = [System.Security.Cryptography.HMACSHA1]::new() # BAD + +# =================================================================== +# ========== TRUE NEGATIVES (should NOT trigger alert) ============== +# =================================================================== + +# --- Safe: HMACSHA256 --- +$hmac = New-Object System.Security.Cryptography.HMACSHA256 # GOOD + +# --- Safe: HMACSHA384 --- +$hmac = [System.Security.Cryptography.HMACSHA384]::new() # GOOD + +# --- Safe: HMACSHA512 --- +$hmac = [System.Security.Cryptography.HMACSHA512]::Create() # GOOD From 424ba6a30b0c1f8d8b18d745e22e87bc9b25a561 Mon Sep 17 00:00:00 2001 From: Chanel Young Date: Mon, 13 Apr 2026 11:11:02 -0700 Subject: [PATCH 2/3] refactor classes to go into existing cryptography modules, added qhelp --- .../cryptography/CryptoAlgorithmNames.qll | 8 ++ .../security/cryptography/CryptoArtifact.qll | 8 ++ .../cryptography/CryptographyModule.qll | 43 +++++++++ .../queries/security/cwe-327/WeakHmac.qhelp | 24 +++++ .../src/queries/security/cwe-327/WeakHmac.ql | 21 +++++ .../src/queries/security/cwe-328/WeakHmac.ql | 92 ------------------- .../WeakHmac/WeakHmac.expected | 0 .../security/cwe-327/WeakHmac/WeakHmac.qlref | 1 + .../{cwe-328 => cwe-327}/WeakHmac/test.ps1 | 0 .../security/cwe-328/WeakHmac/WeakHmac.qlref | 1 - 10 files changed, 105 insertions(+), 93 deletions(-) create mode 100644 powershell/ql/src/queries/security/cwe-327/WeakHmac.qhelp create mode 100644 powershell/ql/src/queries/security/cwe-327/WeakHmac.ql delete mode 100644 powershell/ql/src/queries/security/cwe-328/WeakHmac.ql rename powershell/ql/test/query-tests/security/{cwe-328 => cwe-327}/WeakHmac/WeakHmac.expected (100%) create mode 100644 powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.qlref rename powershell/ql/test/query-tests/security/{cwe-328 => cwe-327}/WeakHmac/test.ps1 (100%) delete mode 100644 powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoAlgorithmNames.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoAlgorithmNames.qll index 8275fdd83e60..c828a804fb85 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoAlgorithmNames.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoAlgorithmNames.qll @@ -22,6 +22,14 @@ predicate isSymmetricAlgorithm(string name) { ] } +predicate isHmacAlgorithm(string name) { + name = + [ + "hmacmd5", "hmacsha1", "hmacripemd160", "hmacsha256", "hmacsha384", "hmacsha512", + "hmacsha3256", "hmacsha3384", "hmacsha3512" + ] +} + predicate isCipherBlockModeAlgorithm(string name) { name = ["cbc", "gcm", "ccm", "cfb", "ofb", "cfb8", "ctr", "openpgp", "xts", "eax", "siv", "ecb"] } diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll index 0aa91bff8c43..eb9cd159d61c 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptoArtifact.qll @@ -29,6 +29,14 @@ abstract class SymmetricAlgorithm extends CryptographicAlgorithm { } } +abstract class HmacAlgorithm extends CryptographicAlgorithm { + final string getHmacName() { + if exists(string n | n = this.getName() and isHmacAlgorithm(n)) + then result = this.getName() + else result = unknownAlgorithm() + } +} + abstract class BlockMode extends CryptographicAlgorithm { final string getBlockModeName() { if exists(string n | n = this.getName() and isCipherBlockModeAlgorithm(n)) diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll index 0e6b2a434733..65ea06550f97 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll @@ -176,6 +176,49 @@ class CipherBlockStringConstExpr extends BlockMode { override string getName() { result = modeName } } +class HmacAlgorithmObjectCreation extends HmacAlgorithm, CryptoAlgorithmObjectCreation { + string algName; + + HmacAlgorithmObjectCreation() { + ( + objectName = "system.security.cryptography." + algName or + objectName = algName + ) and + isHmacAlgorithm(algName) + } + + override string getName() { result = algName } +} + +class HmacAlgorithmCreateCall extends HmacAlgorithm, DataFlow::CallNode { + string algName; + + HmacAlgorithmCreateCall() { + isHmacAlgorithm(algName) and + this = + API::getTopLevelMember("system") + .getMember("security") + .getMember("cryptography") + .getMember(algName) + .getMember(["create", "new"]) + .asCall() + + } + + override string getName() { result = algName } +} + +class HmacAlgorithmCreateFromNameCall extends HmacAlgorithm, CryptoAlgorithmCreateFromNameCall { + string algName; + + HmacAlgorithmCreateFromNameCall() { + objectName = ["", "system.security.cryptography."] + algName and + isHmacAlgorithm(algName) + } + + override string getName() { result = algName } +} + class CipherBlockModeEnum extends BlockMode { string modeName; diff --git a/powershell/ql/src/queries/security/cwe-327/WeakHmac.qhelp b/powershell/ql/src/queries/security/cwe-327/WeakHmac.qhelp new file mode 100644 index 000000000000..3cfae573f25b --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/WeakHmac.qhelp @@ -0,0 +1,24 @@ + + + +

+ HMAC (Hash-based Message Authentication Code) algorithms are used to verify both the + integrity and authenticity of messages. Using weak HMAC algorithms such as HMACMD5, + HMACSHA1, or HMACRIPEMD160 can compromise message authentication, as the underlying + hash functions have known cryptographic weaknesses. +

+
+ +

+ Use a strong HMAC algorithm such as HMACSHA256, HMACSHA384, or HMACSHA512. These are + based on the SHA-2 family of hash functions and provide adequate security for message + authentication. +

+
+ + +
  • NIST, SP 800-131A: Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
  • +
  • CWE-328: Use of Weak Hash.
  • +
    +
    diff --git a/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql b/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql new file mode 100644 index 000000000000..351a17cc74c2 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql @@ -0,0 +1,21 @@ +/** + * @name Use of weak HMAC algorithm + * @description Using weak HMAC algorithms like HMACMD5 or HMACSHA1 can compromise message authentication. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id powershell/microsoft/security/weak-hmac + * @tags security + * external/cwe/cwe-327 + * external/cwe/cwe-328 + */ + +import powershell +import semmle.code.powershell.ApiGraphs +import semmle.code.powershell.dataflow.DataFlow +import semmle.code.powershell.security.cryptography.Concepts + +from HmacAlgorithm hmacAlg +where not hmacAlg.getHmacName() = ["hmacsha256", "hmacsha384", "hmacsha512"] +select hmacAlg, "Use of weak HMAC algorithm: " + hmacAlg.getHmacName() + ". Use HMACSHA256 or stronger." diff --git a/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql b/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql deleted file mode 100644 index 03147d219d04..000000000000 --- a/powershell/ql/src/queries/security/cwe-328/WeakHmac.ql +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @name Use of weak HMAC algorithm - * @description Using weak HMAC algorithms like HMACMD5 or HMACSHA1 can compromise message authentication. - * @kind problem - * @problem.severity warning - * @security-severity 7.5 - * @precision high - * @id powershell/microsoft/security/weak-hmac - * @tags security - * external/cwe/cwe-327 - * external/cwe/cwe-328 - */ - -import powershell -import semmle.code.powershell.ApiGraphs -import semmle.code.powershell.dataflow.DataFlow -import semmle.code.powershell.security.cryptography.CryptographyModule - -/** - * Holds if `name` is a weak HMAC algorithm name (lowercase). - */ -predicate isWeakHmacAlgorithm(string name) { - name = ["hmacmd5", "hmacsha1", "hmacripemd160"] -} - -/** A weak HMAC algorithm instantiated via New-Object. */ -class WeakHmacObjectCreation extends DataFlow::ObjectCreationNode { - string algName; - - WeakHmacObjectCreation() { - exists(string objName | - objName = - this.getExprNode().getExpr().(CallExpr).getAnArgument().getValue().asString().toLowerCase() and - ( - objName = "system.security.cryptography." + algName or - objName = algName - ) and - isWeakHmacAlgorithm(algName) - ) - } - - string getName() { result = algName } -} - -/** A weak HMAC algorithm instantiated via [Type]::Create() or [Type]::new(). */ -class WeakHmacCreateCall extends DataFlow::CallNode { - string algName; - - WeakHmacCreateCall() { - isWeakHmacAlgorithm(algName) and - ( - this = - API::getTopLevelMember("system") - .getMember("security") - .getMember("cryptography") - .getMember(algName) - .getMember("create") - .asCall() - or - this = - API::getTopLevelMember("system") - .getMember("security") - .getMember("cryptography") - .getMember(algName) - .getMember("new") - .asCall() - ) - } - - string getName() { result = algName } -} - -/** A weak HMAC algorithm passed as string to CryptoConfig.CreateFromName(). */ -class WeakHmacCreateFromNameCall extends CryptoAlgorithmCreateFromNameCall { - string algName; - - WeakHmacCreateFromNameCall() { - objectName = ["", "system.security.cryptography."] + algName and - isWeakHmacAlgorithm(algName) - } - - string getHmacName() { result = algName } -} - -from DataFlow::Node node, string algName -where - exists(WeakHmacObjectCreation c | node = c and algName = c.getName()) - or - exists(WeakHmacCreateCall c | node = c and algName = c.getName()) - or - exists(WeakHmacCreateFromNameCall c | node = c and algName = c.getHmacName()) -select node, "Use of weak HMAC algorithm: " + algName + ". Use HMACSHA256 or stronger." diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected b/powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.expected similarity index 100% rename from powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.expected rename to powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.expected diff --git a/powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.qlref b/powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.qlref new file mode 100644 index 000000000000..f6476ddc9c32 --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/WeakHmac/WeakHmac.qlref @@ -0,0 +1 @@ +queries/security/cwe-327/WeakHmac.ql diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 b/powershell/ql/test/query-tests/security/cwe-327/WeakHmac/test.ps1 similarity index 100% rename from powershell/ql/test/query-tests/security/cwe-328/WeakHmac/test.ps1 rename to powershell/ql/test/query-tests/security/cwe-327/WeakHmac/test.ps1 diff --git a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref b/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref deleted file mode 100644 index c226f3332796..000000000000 --- a/powershell/ql/test/query-tests/security/cwe-328/WeakHmac/WeakHmac.qlref +++ /dev/null @@ -1 +0,0 @@ -queries/security/cwe-328/WeakHmac.ql From 1c8fe05048904074b9b2b8772c9978785e467918 Mon Sep 17 00:00:00 2001 From: Chanel Young Date: Thu, 16 Apr 2026 10:23:56 -0700 Subject: [PATCH 3/3] mathias PR feedback, quwery id update --- .../powershell/security/cryptography/CryptographyModule.qll | 5 +---- powershell/ql/src/queries/security/cwe-327/WeakHmac.ql | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll index 65ea06550f97..e0665792e57a 100644 --- a/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll +++ b/powershell/ql/lib/semmle/code/powershell/security/cryptography/CryptographyModule.qll @@ -180,10 +180,7 @@ class HmacAlgorithmObjectCreation extends HmacAlgorithm, CryptoAlgorithmObjectCr string algName; HmacAlgorithmObjectCreation() { - ( - objectName = "system.security.cryptography." + algName or - objectName = algName - ) and + objectName = ["", "system.security.cryptography."] + algName and isHmacAlgorithm(algName) } diff --git a/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql b/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql index 351a17cc74c2..ca97d69da7d9 100644 --- a/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql +++ b/powershell/ql/src/queries/security/cwe-327/WeakHmac.ql @@ -5,7 +5,7 @@ * @problem.severity warning * @security-severity 7.5 * @precision high - * @id powershell/microsoft/security/weak-hmac + * @id powershell/weak-hmac * @tags security * external/cwe/cwe-327 * external/cwe/cwe-328