Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions powershell/ql/src/queries/security/cwe-347/JwtNoneAlgorithm.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>

<p>Using the <code>"none"</code> algorithm when creating a JWT token with
<code>JwtSecurityTokenHandler</code> disables signature verification. This allows attackers to
forge arbitrary tokens that will be accepted as valid, potentially leading to authentication
bypass and privilege escalation.</p>

</overview>
<recommendation>

<p>Always use a secure signing algorithm such as <code>HS256</code>, <code>RS256</code>, or
<code>ES256</code> when creating JWT tokens. Ensure that tokens are signed with a strong secret
or key pair.</p>

</recommendation>
<example>

<p>In this example, a JWT token is created using the <code>"none"</code> algorithm, which produces
an unsigned token:</p>

<sample src="examples/JwtNoneAlgorithmBad.ps1" />

<p>The fix is to use a secure algorithm instead:</p>

<sample src="examples/JwtNoneAlgorithmGood.ps1" />

</example>
<references>

<li>
RFC 7518:
<a href="https://datatracker.ietf.org/doc/html/rfc7518#section-3.6">JSON Web Algorithms - Unsecured JWS</a>.
</li>

<li>
CWE-347:
<a href="https://cwe.mitre.org/data/definitions/347.html">Improper Verification of Cryptographic Signature</a>.
</li>

</references>
</qhelp>
37 changes: 37 additions & 0 deletions powershell/ql/src/queries/security/cwe-347/JwtNoneAlgorithm.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @name JWT none algorithm usage
* @description Using the "none" algorithm for JWT tokens disables signature verification,
* allowing token forgery.
* @kind problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id powershell/jwt-none-algorithm
* @tags security
* external/cwe/cwe-347
*/

import powershell
import semmle.code.powershell.dataflow.DataFlow

/**
* A string literal "none" passed as an algorithm argument to .NET JWT methods
* on a JwtSecurityTokenHandler instance.
*/
class JwtNoneInDotNetCall extends StringConstExpr {
JwtNoneInDotNetCall() {
this.getValueString().toLowerCase() = "none" and
exists(DataFlow::CallNode cn, DataFlow::ObjectCreationNode ocn |
cn.getQualifier().getALocalSource() = ocn and
ocn.getConstructedTypeNode().asExpr().getExpr().(TypeNameExpr).hasQualifiedName("system.identitymodel.tokens.jwt", "jwtsecuritytokenhandler") and
cn.getLowerCaseName() in [
"createtoken", "writetoken", "createjwtsecuritytoken", "createencodedjwt"
] and
cn.getAnArgument().asExpr().getExpr() = this
)
}
}

from JwtNoneInDotNetCall noneAlg
select noneAlg,
"JWT token created with 'none' algorithm via .NET API, disabling signature verification."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$handler = [System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler]::new()

# BAD: Creating a JWT token with the "none" algorithm disables signature verification.
$token = $handler.CreateToken("none")
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$handler = [System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler]::new()

# GOOD: Creating a JWT token with a secure algorithm.
$token = $handler.CreateToken("HS256")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| test.ps1:7:31:7:36 | none | JWT token created with 'none' algorithm via .NET API, disabling signature verification. |
| test.ps1:10:36:10:41 | none | JWT token created with 'none' algorithm via .NET API, disabling signature verification. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
queries/security/cwe-347/JwtNoneAlgorithm.ql
Comment thread
chanel-y marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ===================================================================
# ========== TRUE POSITIVES (should trigger alert) ==================
# ===================================================================

# --- Case 1: .NET JwtSecurityTokenHandler.CreateToken with "none" ---
$handler = [System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler]::new()
$token = $handler.CreateToken("none") # BAD

# --- Case 2: .NET JwtSecurityTokenHandler.CreateEncodedJwt with "none" ---
$token = $handler.CreateEncodedJwt("none") # BAD

# ===================================================================
# ========== TRUE NEGATIVES (should NOT trigger alert) ==============
# ===================================================================

# --- Safe: .NET CreateToken with HS256 ---
$token = $handler.CreateToken("HS256") # GOOD
Loading