Skip to content

Commit ef4a27f

Browse files
committed
Apply code review suggestions
1 parent 3dec222 commit ef4a27f

File tree

6 files changed

+33
-42
lines changed

6 files changed

+33
-42
lines changed

python/ql/src/experimental/Security/CWE-347/JWTEmptyKeyOrAlgorithm.ql

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ import experimental.semmle.python.frameworks.JWT
1414

1515
from JWTEncoding jwtEncoding, string affectedComponent
1616
where
17-
exists( |
18-
affectedComponent = "algorithm" and
19-
isEmptyOrNone(jwtEncoding.getAlgorithm())
20-
or
21-
affectedComponent = "key" and
22-
isEmptyOrNone(jwtEncoding.getKey())
23-
)
24-
select jwtEncoding, affectedComponent, "is empty."
17+
affectedComponent = "algorithm" and
18+
isEmptyOrNone(jwtEncoding.getAlgorithm())
19+
or
20+
affectedComponent = "key" and
21+
isEmptyOrNone(jwtEncoding.getKey())
22+
select jwtEncoding, "This JWT encoding has an empty " + affectedComponent + "."

python/ql/src/experimental/semmle/python/Concepts.qll

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -334,30 +334,26 @@ module JWTEncoding {
334334
* Extend this class to refine existing API models. If you want to model new APIs,
335335
* extend `JWTEncoding::Range` instead.
336336
*/
337-
class JWTEncoding extends DataFlow::Node {
338-
JWTEncoding::Range range;
339-
340-
JWTEncoding() { this = range }
341-
337+
class JWTEncoding extends DataFlow::Node instanceof JWTEncoding::Range {
342338
/**
343339
* Gets the argument containing the payload.
344340
*/
345-
DataFlow::Node getPayload() { result = range.getPayload() }
341+
DataFlow::Node getPayload() { result = super.getPayload() }
346342

347343
/**
348344
* Gets the argument containing the encoding key.
349345
*/
350-
DataFlow::Node getKey() { result = range.getKey() }
346+
DataFlow::Node getKey() { result = super.getKey() }
351347

352348
/**
353349
* Gets the algorithm Node used in the encoding.
354350
*/
355-
DataFlow::Node getAlgorithm() { result = range.getAlgorithm() }
351+
DataFlow::Node getAlgorithm() { result = super.getAlgorithm() }
356352

357353
/**
358354
* Tries to get the algorithm used in the encoding.
359355
*/
360-
string getAlgorithmString() { result = range.getAlgorithmString() }
356+
string getAlgorithmString() { result = super.getAlgorithmString() }
361357
}
362358

363359
/** Provides classes for modeling JWT decoding-related APIs. */
@@ -407,38 +403,34 @@ module JWTDecoding {
407403
* Extend this class to refine existing API models. If you want to model new APIs,
408404
* extend `JWTDecoding::Range` instead.
409405
*/
410-
class JWTDecoding extends DataFlow::Node {
411-
JWTDecoding::Range range;
412-
413-
JWTDecoding() { this = range }
414-
406+
class JWTDecoding extends DataFlow::Node instanceof JWTDecoding::Range {
415407
/**
416408
* Gets the argument containing the payload.
417409
*/
418-
DataFlow::Node getPayload() { result = range.getPayload() }
410+
DataFlow::Node getPayload() { result = super.getPayload() }
419411

420412
/**
421413
* Gets the argument containing the encoding key.
422414
*/
423-
DataFlow::Node getKey() { result = range.getKey() }
415+
DataFlow::Node getKey() { result = super.getKey() }
424416

425417
/**
426418
* Gets the algorithm Node used in the encoding.
427419
*/
428-
DataFlow::Node getAlgorithm() { result = range.getAlgorithm() }
420+
DataFlow::Node getAlgorithm() { result = super.getAlgorithm() }
429421

430422
/**
431423
* Tries to get the algorithm used in the encoding.
432424
*/
433-
string getAlgorithmString() { result = range.getAlgorithmString() }
425+
string getAlgorithmString() { result = super.getAlgorithmString() }
434426

435427
/**
436428
* Gets the options Node used in the encoding.
437429
*/
438-
DataFlow::Node getOptions() { result = range.getOptions() }
430+
DataFlow::Node getOptions() { result = super.getOptions() }
439431

440432
/**
441433
* Checks if the signature gets verified while decoding.
442434
*/
443-
predicate verifiesSignature() { range.verifiesSignature() }
435+
predicate verifiesSignature() { super.verifiesSignature() }
444436
}

python/ql/src/experimental/semmle/python/frameworks/JWT.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ predicate isEmpty(DataFlow::Node arg) {
1414

1515
/** Checks if `None` flows to `arg` */
1616
predicate isNone(DataFlow::Node arg) {
17-
exists( | DataFlow::exprNode(any(None no)).(DataFlow::LocalSourceNode).flowsTo(arg))
17+
DataFlow::exprNode(any(None no)).(DataFlow::LocalSourceNode).flowsTo(arg)
1818
}
1919

2020
/** Checks if `False` flows to `arg` */
2121
predicate isFalse(DataFlow::Node arg) {
22-
exists( | DataFlow::exprNode(any(False falseExpr)).(DataFlow::LocalSourceNode).flowsTo(arg))
22+
DataFlow::exprNode(any(False falseExpr)).(DataFlow::LocalSourceNode).flowsTo(arg)
2323
}

python/ql/src/experimental/semmle/python/libraries/Authlib.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ private module Authlib {
3434
* * `getAlgorithmstring()`'s result would be `HS256`.
3535
*/
3636
private class AuthlibJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
37-
// def encode(self, header, payload, key, check=True):
3837
AuthlibJWTEncodeCall() { this = authlibJWTEncode().getACall() }
3938

4039
override DataFlow::Node getPayload() { result = this.getArg(1) }
@@ -71,7 +70,6 @@ private module Authlib {
7170
* * `getKey()`'s result would be `key`.
7271
*/
7372
private class AuthlibJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
74-
// def decode(self, s, key, claims_cls=None, claims_options=None, claims_params=None):
7573
AuthlibJWTDecodeCall() { this = authlibJWTDecode().getACall() }
7674

7775
override DataFlow::Node getPayload() { result = this.getArg(0) }

python/ql/src/experimental/semmle/python/libraries/PyJWT.qll

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ private module PyJWT {
2626
* * `getAlgorithmstring()`'s result would be `HS256`.
2727
*/
2828
private class PyJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
29-
// def encode(self, payload, key, algorithm="HS256", headers=None, json_encoder=None)
3029
PyJWTEncodeCall() { this = pyjwtEncode().getACall() }
3130

3231
override DataFlow::Node getPayload() {
@@ -65,7 +64,6 @@ private module PyJWT {
6564
* * `verifiesSignature()` predicate would succeed.
6665
*/
6766
private class PyJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
68-
// def decode(self, jwt, key="", algorithms=None, options=None)
6967
PyJWTDecodeCall() { this = pyjwtDecode().getACall() }
7068

7169
override DataFlow::Node getPayload() { result in [this.getArg(0), this.getArgByName("jwt")] }
@@ -88,13 +86,20 @@ private module PyJWT {
8886
}
8987

9088
override predicate verifiesSignature() {
91-
// jwt.decode(token, "key", "HS256")
92-
not exists(this.getArgByName("verify")) and not exists(this.getOptions())
89+
this.hasNoVerifyArgumentOrOptions()
9390
or
94-
// jwt.decode(token, verify=False)
95-
not isFalse(this.getArgByName("verify")) and
96-
// jwt.decode(token, key, options={"verify_signature": False})
97-
not exists(KeyValuePair optionsDict, NameConstant falseName |
91+
not this.hasVerifySetToFalse() and
92+
not this.hasVerifySignatureSetToFalse()
93+
}
94+
95+
predicate hasNoVerifyArgumentOrOptions() {
96+
not exists(this.getArgByName("verify")) and not exists(this.getOptions())
97+
}
98+
99+
predicate hasVerifySetToFalse() { isFalse(this.getArgByName("verify")) }
100+
101+
predicate hasVerifySignatureSetToFalse() {
102+
exists(KeyValuePair optionsDict, NameConstant falseName |
98103
falseName.getId() = "False" and
99104
optionsDict = this.getOptions().asExpr().(Dict).getItems().getAnItem() and
100105
optionsDict.getKey().(Str_).getS().matches("%verify%") and

python/ql/src/experimental/semmle/python/libraries/PythonJose.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ private module PythonJose {
2929
* * `getAlgorithmstring()`'s result would be `HS256`.
3030
*/
3131
private class JoseJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
32-
// def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None):
3332
JoseJWTEncodeCall() { this = joseJWTEncode().getACall() }
3433

3534
override DataFlow::Node getPayload() { result = this.getArg(0) }
@@ -66,7 +65,6 @@ private module PythonJose {
6665
* * `verifiesSignature()` predicate would succeed.
6766
*/
6867
private class JoseJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
69-
// def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
7068
JoseJWTDecodeCall() { this = joseJWTDecode().getACall() }
7169

7270
override DataFlow::Node getPayload() { result = this.getArg(0) }

0 commit comments

Comments
 (0)