Skip to content

Commit f5a6485

Browse files
committed
JS: Port experimental decodeJwtWithoutVerificationLocalSource
1 parent 72e5226 commit f5a6485

File tree

2 files changed

+89
-150
lines changed

2 files changed

+89
-150
lines changed

javascript/ql/src/experimental/Security/CWE-347/decodeJwtWithoutVerificationLocalSource.ql

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,43 @@
1111
*/
1212

1313
import javascript
14-
import DataFlow::PathGraph
1514
import JWT
1615

17-
class Configuration extends TaintTracking::Configuration {
18-
Configuration() { this = "jsonwebtoken without any signature verification" }
19-
20-
override predicate isSource(DataFlow::Node source) {
16+
module DecodeWithoutVerificationConfig implements DataFlow::ConfigSig {
17+
predicate isSource(DataFlow::Node source) {
2118
source = [unverifiedDecode(), verifiedDecode()].getALocalSource()
2219
}
2320

24-
override predicate isSink(DataFlow::Node sink) {
21+
predicate isSink(DataFlow::Node sink) {
2522
sink = unverifiedDecode()
2623
or
2724
sink = verifiedDecode()
2825
}
2926
}
3027

28+
module DecodeWithoutVerificationFlow = TaintTracking::Global<DecodeWithoutVerificationConfig>;
29+
3130
/** Holds if `source` flows to the first parameter of jsonwebtoken.verify */
32-
predicate isSafe(Configuration cfg, DataFlow::Node source) {
33-
exists(DataFlow::Node sink |
34-
cfg.hasFlow(source, sink) and
35-
sink = verifiedDecode()
36-
)
31+
predicate isSafe(DataFlow::Node source) {
32+
DecodeWithoutVerificationFlow::flow(source, verifiedDecode())
3733
}
3834

3935
/**
4036
* Holds if:
4137
* - `source` does not flow to the first parameter of `jsonwebtoken.verify`, and
4238
* - `source` flows to the first parameter of `jsonwebtoken.decode`
4339
*/
44-
predicate isVulnerable(Configuration cfg, DataFlow::Node source, DataFlow::Node sink) {
45-
not isSafe(cfg, source) and // i.e., source does not flow to a verify call
46-
cfg.hasFlow(source, sink) and // but it does flow to something else
40+
predicate isVulnerable(DataFlow::Node source, DataFlow::Node sink) {
41+
not isSafe(source) and // i.e., source does not flow to a verify call
42+
DecodeWithoutVerificationFlow::flow(source, sink) and // but it does flow to something else
4743
sink = unverifiedDecode() // and that something else is a call to decode.
4844
}
4945

50-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
46+
import DecodeWithoutVerificationFlow::PathGraph
47+
48+
from DecodeWithoutVerificationFlow::PathNode source, DecodeWithoutVerificationFlow::PathNode sink
5149
where
52-
cfg.hasFlowPath(source, sink) and
53-
isVulnerable(cfg, source.getNode(), sink.getNode())
50+
DecodeWithoutVerificationFlow::flowPath(source, sink) and
51+
isVulnerable(source.getNode(), sink.getNode())
5452
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
5553
"without signature verification"

javascript/ql/test/experimental/Security/CWE-347/localsource/decodeJwtWithoutVerificationLocalSource.expected

Lines changed: 74 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,78 @@
1-
nodes
2-
| JsonWebToken.js:13:11:13:28 | UserToken |
3-
| JsonWebToken.js:13:23:13:28 | aJwt() |
4-
| JsonWebToken.js:13:23:13:28 | aJwt() |
5-
| JsonWebToken.js:16:28:16:36 | UserToken |
6-
| JsonWebToken.js:16:28:16:36 | UserToken |
7-
| JsonWebToken.js:20:11:20:28 | UserToken |
8-
| JsonWebToken.js:20:23:20:28 | aJwt() |
9-
| JsonWebToken.js:20:23:20:28 | aJwt() |
10-
| JsonWebToken.js:23:28:23:36 | UserToken |
11-
| JsonWebToken.js:23:28:23:36 | UserToken |
12-
| JsonWebToken.js:24:28:24:36 | UserToken |
13-
| JsonWebToken.js:24:28:24:36 | UserToken |
14-
| JsonWebToken.js:28:11:28:28 | UserToken |
15-
| JsonWebToken.js:28:23:28:28 | aJwt() |
16-
| JsonWebToken.js:28:23:28:28 | aJwt() |
17-
| JsonWebToken.js:31:28:31:36 | UserToken |
18-
| JsonWebToken.js:31:28:31:36 | UserToken |
19-
| JsonWebToken.js:35:11:35:28 | UserToken |
20-
| JsonWebToken.js:35:23:35:28 | aJwt() |
21-
| JsonWebToken.js:35:23:35:28 | aJwt() |
22-
| JsonWebToken.js:38:28:38:36 | UserToken |
23-
| JsonWebToken.js:38:28:38:36 | UserToken |
24-
| JsonWebToken.js:39:28:39:36 | UserToken |
25-
| JsonWebToken.js:39:28:39:36 | UserToken |
26-
| JsonWebToken.js:43:11:43:28 | UserToken |
27-
| JsonWebToken.js:43:23:43:28 | aJwt() |
28-
| JsonWebToken.js:43:23:43:28 | aJwt() |
29-
| JsonWebToken.js:46:28:46:36 | UserToken |
30-
| JsonWebToken.js:46:28:46:36 | UserToken |
31-
| JsonWebToken.js:47:28:47:36 | UserToken |
32-
| JsonWebToken.js:47:28:47:36 | UserToken |
33-
| jose.js:12:11:12:28 | UserToken |
34-
| jose.js:12:23:12:28 | aJwt() |
35-
| jose.js:12:23:12:28 | aJwt() |
36-
| jose.js:15:20:15:28 | UserToken |
37-
| jose.js:15:20:15:28 | UserToken |
38-
| jose.js:19:11:19:28 | UserToken |
39-
| jose.js:19:23:19:28 | aJwt() |
40-
| jose.js:19:23:19:28 | aJwt() |
41-
| jose.js:22:20:22:28 | UserToken |
42-
| jose.js:22:20:22:28 | UserToken |
43-
| jose.js:23:26:23:34 | UserToken |
44-
| jose.js:23:26:23:34 | UserToken |
45-
| jose.js:27:11:27:28 | UserToken |
46-
| jose.js:27:23:27:28 | aJwt() |
47-
| jose.js:27:23:27:28 | aJwt() |
48-
| jose.js:30:26:30:34 | UserToken |
49-
| jose.js:30:26:30:34 | UserToken |
50-
| jwtDecode.js:13:11:13:28 | UserToken |
51-
| jwtDecode.js:13:23:13:28 | aJwt() |
52-
| jwtDecode.js:13:23:13:28 | aJwt() |
53-
| jwtDecode.js:17:16:17:24 | UserToken |
54-
| jwtDecode.js:17:16:17:24 | UserToken |
55-
| jwtSimple.js:13:11:13:28 | UserToken |
56-
| jwtSimple.js:13:23:13:28 | aJwt() |
57-
| jwtSimple.js:13:23:13:28 | aJwt() |
58-
| jwtSimple.js:16:23:16:31 | UserToken |
59-
| jwtSimple.js:16:23:16:31 | UserToken |
60-
| jwtSimple.js:20:11:20:28 | UserToken |
61-
| jwtSimple.js:20:23:20:28 | aJwt() |
62-
| jwtSimple.js:20:23:20:28 | aJwt() |
63-
| jwtSimple.js:23:23:23:31 | UserToken |
64-
| jwtSimple.js:23:23:23:31 | UserToken |
65-
| jwtSimple.js:24:23:24:31 | UserToken |
66-
| jwtSimple.js:24:23:24:31 | UserToken |
67-
| jwtSimple.js:28:11:28:28 | UserToken |
68-
| jwtSimple.js:28:23:28:28 | aJwt() |
69-
| jwtSimple.js:28:23:28:28 | aJwt() |
70-
| jwtSimple.js:31:23:31:31 | UserToken |
71-
| jwtSimple.js:31:23:31:31 | UserToken |
72-
| jwtSimple.js:32:23:32:31 | UserToken |
73-
| jwtSimple.js:32:23:32:31 | UserToken |
741
edges
75-
| JsonWebToken.js:13:11:13:28 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
76-
| JsonWebToken.js:13:11:13:28 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
77-
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:11:13:28 | UserToken |
78-
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:11:13:28 | UserToken |
79-
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
80-
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
81-
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
82-
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
83-
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:11:20:28 | UserToken |
84-
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:11:20:28 | UserToken |
85-
| JsonWebToken.js:28:11:28:28 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
86-
| JsonWebToken.js:28:11:28:28 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
87-
| JsonWebToken.js:28:23:28:28 | aJwt() | JsonWebToken.js:28:11:28:28 | UserToken |
88-
| JsonWebToken.js:28:23:28:28 | aJwt() | JsonWebToken.js:28:11:28:28 | UserToken |
89-
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
90-
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
91-
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
92-
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
93-
| JsonWebToken.js:35:23:35:28 | aJwt() | JsonWebToken.js:35:11:35:28 | UserToken |
94-
| JsonWebToken.js:35:23:35:28 | aJwt() | JsonWebToken.js:35:11:35:28 | UserToken |
95-
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
96-
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
97-
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
98-
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
99-
| JsonWebToken.js:43:23:43:28 | aJwt() | JsonWebToken.js:43:11:43:28 | UserToken |
100-
| JsonWebToken.js:43:23:43:28 | aJwt() | JsonWebToken.js:43:11:43:28 | UserToken |
101-
| jose.js:12:11:12:28 | UserToken | jose.js:15:20:15:28 | UserToken |
102-
| jose.js:12:11:12:28 | UserToken | jose.js:15:20:15:28 | UserToken |
103-
| jose.js:12:23:12:28 | aJwt() | jose.js:12:11:12:28 | UserToken |
104-
| jose.js:12:23:12:28 | aJwt() | jose.js:12:11:12:28 | UserToken |
105-
| jose.js:19:11:19:28 | UserToken | jose.js:22:20:22:28 | UserToken |
106-
| jose.js:19:11:19:28 | UserToken | jose.js:22:20:22:28 | UserToken |
107-
| jose.js:19:11:19:28 | UserToken | jose.js:23:26:23:34 | UserToken |
108-
| jose.js:19:11:19:28 | UserToken | jose.js:23:26:23:34 | UserToken |
109-
| jose.js:19:23:19:28 | aJwt() | jose.js:19:11:19:28 | UserToken |
110-
| jose.js:19:23:19:28 | aJwt() | jose.js:19:11:19:28 | UserToken |
111-
| jose.js:27:11:27:28 | UserToken | jose.js:30:26:30:34 | UserToken |
112-
| jose.js:27:11:27:28 | UserToken | jose.js:30:26:30:34 | UserToken |
113-
| jose.js:27:23:27:28 | aJwt() | jose.js:27:11:27:28 | UserToken |
114-
| jose.js:27:23:27:28 | aJwt() | jose.js:27:11:27:28 | UserToken |
115-
| jwtDecode.js:13:11:13:28 | UserToken | jwtDecode.js:17:16:17:24 | UserToken |
116-
| jwtDecode.js:13:11:13:28 | UserToken | jwtDecode.js:17:16:17:24 | UserToken |
117-
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:11:13:28 | UserToken |
118-
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:11:13:28 | UserToken |
119-
| jwtSimple.js:13:11:13:28 | UserToken | jwtSimple.js:16:23:16:31 | UserToken |
120-
| jwtSimple.js:13:11:13:28 | UserToken | jwtSimple.js:16:23:16:31 | UserToken |
121-
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:11:13:28 | UserToken |
122-
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:11:13:28 | UserToken |
123-
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:23:23:23:31 | UserToken |
124-
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:23:23:23:31 | UserToken |
125-
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:24:23:24:31 | UserToken |
126-
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:24:23:24:31 | UserToken |
127-
| jwtSimple.js:20:23:20:28 | aJwt() | jwtSimple.js:20:11:20:28 | UserToken |
128-
| jwtSimple.js:20:23:20:28 | aJwt() | jwtSimple.js:20:11:20:28 | UserToken |
129-
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:31:23:31:31 | UserToken |
130-
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:31:23:31:31 | UserToken |
131-
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:32:23:32:31 | UserToken |
132-
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:32:23:32:31 | UserToken |
133-
| jwtSimple.js:28:23:28:28 | aJwt() | jwtSimple.js:28:11:28:28 | UserToken |
134-
| jwtSimple.js:28:23:28:28 | aJwt() | jwtSimple.js:28:11:28:28 | UserToken |
2+
| JsonWebToken.js:13:11:13:28 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken | provenance | |
3+
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:11:13:28 | UserToken | provenance | |
4+
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken | provenance | |
5+
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken | provenance | |
6+
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:11:20:28 | UserToken | provenance | |
7+
| JsonWebToken.js:28:11:28:28 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken | provenance | |
8+
| JsonWebToken.js:28:23:28:28 | aJwt() | JsonWebToken.js:28:11:28:28 | UserToken | provenance | |
9+
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken | provenance | |
10+
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken | provenance | |
11+
| JsonWebToken.js:35:23:35:28 | aJwt() | JsonWebToken.js:35:11:35:28 | UserToken | provenance | |
12+
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken | provenance | |
13+
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken | provenance | |
14+
| JsonWebToken.js:43:23:43:28 | aJwt() | JsonWebToken.js:43:11:43:28 | UserToken | provenance | |
15+
| jose.js:12:11:12:28 | UserToken | jose.js:15:20:15:28 | UserToken | provenance | |
16+
| jose.js:12:23:12:28 | aJwt() | jose.js:12:11:12:28 | UserToken | provenance | |
17+
| jose.js:19:11:19:28 | UserToken | jose.js:22:20:22:28 | UserToken | provenance | |
18+
| jose.js:19:11:19:28 | UserToken | jose.js:23:26:23:34 | UserToken | provenance | |
19+
| jose.js:19:23:19:28 | aJwt() | jose.js:19:11:19:28 | UserToken | provenance | |
20+
| jose.js:27:11:27:28 | UserToken | jose.js:30:26:30:34 | UserToken | provenance | |
21+
| jose.js:27:23:27:28 | aJwt() | jose.js:27:11:27:28 | UserToken | provenance | |
22+
| jwtDecode.js:13:11:13:28 | UserToken | jwtDecode.js:17:16:17:24 | UserToken | provenance | |
23+
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:11:13:28 | UserToken | provenance | |
24+
| jwtSimple.js:13:11:13:28 | UserToken | jwtSimple.js:16:23:16:31 | UserToken | provenance | |
25+
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:11:13:28 | UserToken | provenance | |
26+
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:23:23:23:31 | UserToken | provenance | |
27+
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:24:23:24:31 | UserToken | provenance | |
28+
| jwtSimple.js:20:23:20:28 | aJwt() | jwtSimple.js:20:11:20:28 | UserToken | provenance | |
29+
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:31:23:31:31 | UserToken | provenance | |
30+
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:32:23:32:31 | UserToken | provenance | |
31+
| jwtSimple.js:28:23:28:28 | aJwt() | jwtSimple.js:28:11:28:28 | UserToken | provenance | |
32+
nodes
33+
| JsonWebToken.js:13:11:13:28 | UserToken | semmle.label | UserToken |
34+
| JsonWebToken.js:13:23:13:28 | aJwt() | semmle.label | aJwt() |
35+
| JsonWebToken.js:16:28:16:36 | UserToken | semmle.label | UserToken |
36+
| JsonWebToken.js:20:11:20:28 | UserToken | semmle.label | UserToken |
37+
| JsonWebToken.js:20:23:20:28 | aJwt() | semmle.label | aJwt() |
38+
| JsonWebToken.js:23:28:23:36 | UserToken | semmle.label | UserToken |
39+
| JsonWebToken.js:24:28:24:36 | UserToken | semmle.label | UserToken |
40+
| JsonWebToken.js:28:11:28:28 | UserToken | semmle.label | UserToken |
41+
| JsonWebToken.js:28:23:28:28 | aJwt() | semmle.label | aJwt() |
42+
| JsonWebToken.js:31:28:31:36 | UserToken | semmle.label | UserToken |
43+
| JsonWebToken.js:35:11:35:28 | UserToken | semmle.label | UserToken |
44+
| JsonWebToken.js:35:23:35:28 | aJwt() | semmle.label | aJwt() |
45+
| JsonWebToken.js:38:28:38:36 | UserToken | semmle.label | UserToken |
46+
| JsonWebToken.js:39:28:39:36 | UserToken | semmle.label | UserToken |
47+
| JsonWebToken.js:43:11:43:28 | UserToken | semmle.label | UserToken |
48+
| JsonWebToken.js:43:23:43:28 | aJwt() | semmle.label | aJwt() |
49+
| JsonWebToken.js:46:28:46:36 | UserToken | semmle.label | UserToken |
50+
| JsonWebToken.js:47:28:47:36 | UserToken | semmle.label | UserToken |
51+
| jose.js:12:11:12:28 | UserToken | semmle.label | UserToken |
52+
| jose.js:12:23:12:28 | aJwt() | semmle.label | aJwt() |
53+
| jose.js:15:20:15:28 | UserToken | semmle.label | UserToken |
54+
| jose.js:19:11:19:28 | UserToken | semmle.label | UserToken |
55+
| jose.js:19:23:19:28 | aJwt() | semmle.label | aJwt() |
56+
| jose.js:22:20:22:28 | UserToken | semmle.label | UserToken |
57+
| jose.js:23:26:23:34 | UserToken | semmle.label | UserToken |
58+
| jose.js:27:11:27:28 | UserToken | semmle.label | UserToken |
59+
| jose.js:27:23:27:28 | aJwt() | semmle.label | aJwt() |
60+
| jose.js:30:26:30:34 | UserToken | semmle.label | UserToken |
61+
| jwtDecode.js:13:11:13:28 | UserToken | semmle.label | UserToken |
62+
| jwtDecode.js:13:23:13:28 | aJwt() | semmle.label | aJwt() |
63+
| jwtDecode.js:17:16:17:24 | UserToken | semmle.label | UserToken |
64+
| jwtSimple.js:13:11:13:28 | UserToken | semmle.label | UserToken |
65+
| jwtSimple.js:13:23:13:28 | aJwt() | semmle.label | aJwt() |
66+
| jwtSimple.js:16:23:16:31 | UserToken | semmle.label | UserToken |
67+
| jwtSimple.js:20:11:20:28 | UserToken | semmle.label | UserToken |
68+
| jwtSimple.js:20:23:20:28 | aJwt() | semmle.label | aJwt() |
69+
| jwtSimple.js:23:23:23:31 | UserToken | semmle.label | UserToken |
70+
| jwtSimple.js:24:23:24:31 | UserToken | semmle.label | UserToken |
71+
| jwtSimple.js:28:11:28:28 | UserToken | semmle.label | UserToken |
72+
| jwtSimple.js:28:23:28:28 | aJwt() | semmle.label | aJwt() |
73+
| jwtSimple.js:31:23:31:31 | UserToken | semmle.label | UserToken |
74+
| jwtSimple.js:32:23:32:31 | UserToken | semmle.label | UserToken |
75+
subpaths
13576
#select
13677
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:16:28:16:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:16:28:16:36 | UserToken | without signature verification |
13778
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:23:28:23:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:23:28:23:36 | UserToken | without signature verification |

0 commit comments

Comments
 (0)