From 59eff318ad7f60e5da61272898f59a5ad52bcf15 Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Mon, 27 Jul 2026 14:07:14 -0700 Subject: [PATCH 1/3] adding powershell dont install root cert query --- .../cwe-327/DontInstallRootCert.qhelp | 38 +++++++++++++++++++ .../security/cwe-327/DontInstallRootCert.ql | 32 ++++++++++++++++ .../examples/DontInstallRootCertBad.ps1 | 3 ++ .../examples/DontInstallRootCertGood.ps1 | 2 + 4 files changed, 75 insertions(+) create mode 100644 powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.qhelp create mode 100644 powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql create mode 100644 powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertBad.ps1 create mode 100644 powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertGood.ps1 diff --git a/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.qhelp b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.qhelp new file mode 100644 index 000000000000..f4f21ebeaa4d --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.qhelp @@ -0,0 +1,38 @@ + + + +

+ Adding certificates to the system root certificate store (e.g., + Cert:\LocalMachine\Root) weakens security for all applications running on + the same machine. Any certificate in the root store is trusted as a certificate authority, + which means a malicious or compromised certificate could be used to intercept encrypted + communications or impersonate trusted services for all users on the system. +

+
+ +

+ Instead of importing certificates into the root store, use an application-specific or + user-specific certificate store such as Cert:\CurrentUser\My or + Cert:\LocalMachine\My. If root trust is genuinely required, ensure the + operation is restricted to controlled environments and the certificate is removed after use. +

+
+ +

+ The following example imports a certificate directly into the root store, weakening security + for all applications on the system: +

+ + +

+ The following example imports the certificate into a user-specific store, limiting the + scope of trust: +

+ +
+ +
  • Microsoft: Import-Certificate.
  • +
  • Microsoft: Import-PfxCertificate.
  • +
  • CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
  • +
    +
    diff --git a/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql new file mode 100644 index 000000000000..73d0ad1afd07 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql @@ -0,0 +1,32 @@ +/** + * @name Do not add certificates to the system root store + * @description Adding certificates to the system root certificate store weakens security for all + * applications running on the same machine by trusting potentially untrusted + * certificate authorities. + * @kind problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id powershell/adding-cert-to-root-store + * @tags security + * external/cwe/cwe-327 + */ + +import powershell + +/** + * A call to `Import-Certificate` or `Import-PfxCertificate` that targets the root certificate store. + */ +class ImportCertToRootStore extends CmdCall { + ImportCertToRootStore() { + this.getAName() = ["Import-Certificate", "Import-PfxCertificate"] and + exists(Expr loc | + loc = this.getNamedArgument("certstorelocation") and + loc.getValue().stringMatches("%Root%") + ) + } +} + +from ImportCertToRootStore call +select call, + "This call adds a certificate to the root certificate store, which weakens security for all applications on the machine." diff --git a/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertBad.ps1 b/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertBad.ps1 new file mode 100644 index 000000000000..edb2556c961a --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertBad.ps1 @@ -0,0 +1,3 @@ +# BAD: Importing a certificate into the root store weakens security for all +# applications on the machine. +Import-Certificate -FilePath "C:\certs\my-cert.cer" -CertStoreLocation Cert:\LocalMachine\Root diff --git a/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertGood.ps1 b/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertGood.ps1 new file mode 100644 index 000000000000..ee84f9bdd2f8 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-327/examples/DontInstallRootCertGood.ps1 @@ -0,0 +1,2 @@ +# GOOD: Importing a certificate into a user-specific store limits the scope of trust. +Import-Certificate -FilePath "C:\certs\my-cert.cer" -CertStoreLocation Cert:\CurrentUser\My From 84bc51c00c3a4bcd133c12f9eb3724b8719a58ab Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Mon, 10 Aug 2026 13:21:03 -0700 Subject: [PATCH 2/3] PS: fix DontInstallRootCert store-location match stringMatches on ConstantValue is exact case-insensitive equality, not a wildcard LIKE, so '%Root%' never matched. Use asString().matches() instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f7896af6-648f-4c43-9fe1-245ccdb94e4d --- .../ql/src/queries/security/cwe-327/DontInstallRootCert.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql index 73d0ad1afd07..54427b7a8270 100644 --- a/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql +++ b/powershell/ql/src/queries/security/cwe-327/DontInstallRootCert.ql @@ -22,7 +22,7 @@ class ImportCertToRootStore extends CmdCall { this.getAName() = ["Import-Certificate", "Import-PfxCertificate"] and exists(Expr loc | loc = this.getNamedArgument("certstorelocation") and - loc.getValue().stringMatches("%Root%") + loc.getValue().asString().toLowerCase().matches("%root%") ) } } From 3b719c7fcfa31c5b26ae49cea2892e0f37aa9f8c Mon Sep 17 00:00:00 2001 From: chanelyoung Date: Mon, 10 Aug 2026 13:29:28 -0700 Subject: [PATCH 3/3] PS: add test for DontInstallRootCert query Covers root-store imports (LocalMachine\Root, CurrentUser\Root, mixed casing) and non-root stores to guard against the store-location match regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f7896af6-648f-4c43-9fe1-245ccdb94e4d --- .../DontInstallRootCert.expected | 3 +++ .../DontInstallRootCert.qlref | 2 ++ .../cwe-327/DontInstallRootCert/test.ps1 | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.expected create mode 100644 powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.qlref create mode 100644 powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/test.ps1 diff --git a/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.expected b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.expected new file mode 100644 index 000000000000..15ed20206e26 --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.expected @@ -0,0 +1,3 @@ +| test.ps1:2:1:2:94 | Call to import-certificate | This call adds a certificate to the root certificate store, which weakens security for all applications on the machine. | +| test.ps1:5:1:5:96 | Call to import-pfxcertificate | This call adds a certificate to the root certificate store, which weakens security for all applications on the machine. | +| test.ps1:8:1:8:94 | Call to import-certificate | This call adds a certificate to the root certificate store, which weakens security for all applications on the machine. | diff --git a/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.qlref b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.qlref new file mode 100644 index 000000000000..0072efed6dcd --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/DontInstallRootCert.qlref @@ -0,0 +1,2 @@ +query: queries/security/cwe-327/DontInstallRootCert.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/test.ps1 b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/test.ps1 new file mode 100644 index 000000000000..d4487e38ba8e --- /dev/null +++ b/powershell/ql/test/query-tests/security/cwe-327/DontInstallRootCert/test.ps1 @@ -0,0 +1,17 @@ +# BAD: importing into the machine root store. +Import-Certificate -FilePath "C:\certs\my-cert.cer" -CertStoreLocation Cert:\LocalMachine\Root # $ Alert + +# BAD: importing a PFX into the current-user root store. +Import-PfxCertificate -FilePath "C:\certs\my-cert.pfx" -CertStoreLocation Cert:\CurrentUser\Root # $ Alert + +# BAD: casing should not matter. +Import-Certificate -FilePath "C:\certs\my-cert.cer" -CertStoreLocation cert:\localmachine\root # $ Alert + +# GOOD: user-specific personal store. +Import-Certificate -FilePath "C:\certs\my-cert.cer" -CertStoreLocation Cert:\CurrentUser\My + +# GOOD: machine personal store. +Import-PfxCertificate -FilePath "C:\certs\my-cert.pfx" -CertStoreLocation Cert:\LocalMachine\My + +# GOOD: no store location specified. +Import-Certificate -FilePath "C:\certs\my-cert.cer"