Skip to content

Commit 701e3d7

Browse files
committed
add same query but with local source support to comply with the CVE-2021-37580
1 parent 96c142b commit 701e3d7

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @name Missing JWT signature check
3+
* @description Failing to check the Json Web Token (JWT) signature may allow an attacker to forge their own tokens.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision medium
8+
* @id java/missing-jwt-signature-check-auth0-local-source
9+
* @tags security
10+
* external/cwe/cwe-347
11+
*/
12+
13+
import java
14+
import semmle.code.java.dataflow.FlowSources
15+
16+
module JwtAuth0 {
17+
class PayloadType extends RefType {
18+
PayloadType() { this.hasQualifiedName("com.auth0.jwt.interfaces", "Payload") }
19+
}
20+
21+
class JwtType extends RefType {
22+
JwtType() { this.hasQualifiedName("com.auth0.jwt", "JWT") }
23+
}
24+
25+
class JwtVerifierType extends RefType {
26+
JwtVerifierType() { this.hasQualifiedName("com.auth0.jwt", "JWTVerifier") }
27+
}
28+
29+
/**
30+
* A Method that returns a Decoded Claim of JWT
31+
*/
32+
class GetPayload extends MethodCall {
33+
GetPayload() {
34+
this.getCallee().getDeclaringType() instanceof PayloadType and
35+
this.getCallee().hasName(["getClaim", "getIssuedAt"])
36+
}
37+
}
38+
39+
/**
40+
* A Method that Decode JWT without signature verification
41+
*/
42+
class Decode extends MethodCall {
43+
Decode() {
44+
this.getCallee().getDeclaringType() instanceof JwtType and
45+
this.getCallee().hasName("decode")
46+
}
47+
}
48+
49+
/**
50+
* A Method that Decode JWT with signature verification
51+
*/
52+
class Verify extends MethodCall {
53+
Verify() {
54+
this.getCallee().getDeclaringType() instanceof JwtVerifierType and
55+
this.getCallee().hasName("verify")
56+
}
57+
}
58+
}
59+
60+
module JwtDecodeConfig implements DataFlow::ConfigSig {
61+
predicate isSource(DataFlow::Node source) {
62+
63+
exists(Variable v |
64+
source.asExpr() = v.getInitializer() and
65+
v.getType().hasName("String")
66+
) and
67+
not FlowToJwtVerify::flow(source, _)
68+
}
69+
70+
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(JwtAuth0::GetPayload a) }
71+
72+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
73+
// Decode Should be one of the middle nodes
74+
exists(JwtAuth0::Decode a |
75+
nodeFrom.asExpr() = a.getArgument(0) and
76+
nodeTo.asExpr() = a
77+
)
78+
or
79+
exists(JwtAuth0::Verify a |
80+
nodeFrom.asExpr() = a.getArgument(0) and
81+
nodeTo.asExpr() = a
82+
)
83+
or
84+
exists(JwtAuth0::GetPayload a |
85+
nodeFrom.asExpr() = a.getQualifier() and
86+
nodeTo.asExpr() = a
87+
)
88+
}
89+
}
90+
91+
module FlowToJwtVerifyConfig implements DataFlow::ConfigSig {
92+
predicate isSource(DataFlow::Node source) {
93+
exists(Variable v |
94+
source.asExpr() = v.getInitializer() and
95+
v.getType().hasName("String")
96+
)
97+
}
98+
99+
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(JwtAuth0::Verify a).getArgument(0) }
100+
}
101+
102+
module JwtDecode = TaintTracking::Global<JwtDecodeConfig>;
103+
104+
module FlowToJwtVerify = TaintTracking::Global<FlowToJwtVerifyConfig>;
105+
106+
import JwtDecode::PathGraph
107+
108+
from JwtDecode::PathNode source, JwtDecode::PathNode sink
109+
where JwtDecode::flowPath(source, sink)
110+
select sink.getNode(), source, sink, "This parses a $@, but the signature is not verified.",
111+
source.getNode(), "JWT"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
edges
2+
| JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | provenance | Src:MaD:44684 |
3+
| JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | JwtNoVerifier.java:72:38:72:55 | token : String | provenance | |
4+
| JwtNoVerifier.java:72:38:72:55 | token : String | JwtNoVerifier.java:73:37:73:41 | token : String | provenance | |
5+
| JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | provenance | |
6+
| JwtNoVerifier.java:73:37:73:41 | token : String | JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | provenance | Config |
7+
| JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | provenance | MaD:43977 |
8+
| JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | provenance | MaD:43979 |
9+
| JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | provenance | |
10+
| JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | JwtNoVerifier.java:74:45:74:69 | getClaim(...) | provenance | Config |
11+
nodes
12+
| JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | semmle.label | getParameter(...) : String |
13+
| JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | semmle.label | JwtToken2 : String |
14+
| JwtNoVerifier.java:72:38:72:55 | token : String | semmle.label | token : String |
15+
| JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | semmle.label | decode(...) : DecodedJWT |
16+
| JwtNoVerifier.java:73:37:73:41 | token : String | semmle.label | token : String |
17+
| JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | semmle.label | of(...) : Optional [<element>] : DecodedJWT |
18+
| JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | semmle.label | jwt : DecodedJWT |
19+
| JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | semmle.label | item : DecodedJWT |
20+
| JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | semmle.label | item : DecodedJWT |
21+
| JwtNoVerifier.java:74:45:74:69 | getClaim(...) | semmle.label | getClaim(...) |
22+
subpaths
23+
#select
24+
| JwtNoVerifier.java:74:45:74:69 | getClaim(...) | JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | JwtNoVerifier.java:74:45:74:69 | getClaim(...) | This parses a $@, but the signature is not verified. | JwtNoVerifier.java:42:28:42:55 | getParameter(...) | JWT |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-347/Auth0NoVerifierLocalSource.ql

0 commit comments

Comments
 (0)