Skip to content

Commit 3ee2fa0

Browse files
committed
Rust: Add request forgery query
1 parent df2a988 commit 3ee2fa0

File tree

4 files changed

+200
-0
lines changed

4 files changed

+200
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Provides classes and predicates for reasoning about request forgery
3+
* vulnerabilities.
4+
*/
5+
6+
import rust
7+
private import codeql.rust.dataflow.DataFlow
8+
private import codeql.rust.dataflow.FlowSink
9+
private import codeql.rust.dataflow.FlowSource
10+
private import codeql.rust.Concepts
11+
private import codeql.rust.security.CleartextTransmissionExtensions
12+
13+
/**
14+
* Provides default sources, sinks and barriers for detecting request forgery
15+
* vulnerabilities, as well as extension points for adding your own.
16+
*/
17+
module RequestForgery {
18+
/**
19+
* A data flow source for request forgery vulnerabilities.
20+
*/
21+
abstract class Source extends DataFlow::Node { }
22+
23+
/**
24+
* A data flow sink for request forgery vulnerabilities.
25+
*/
26+
abstract class Sink extends QuerySink::Range {
27+
/**
28+
* Gets the name of a part of the request that may be tainted by this sink,
29+
* such as the URL or the host.
30+
*/
31+
override string getSinkType() { result = "RequestForgery" }
32+
}
33+
34+
/**
35+
* A barrier for request forgery vulnerabilities.
36+
*/
37+
abstract class Barrier extends DataFlow::Node { }
38+
39+
/**
40+
* An active threat-model source, considered as a flow source.
41+
*/
42+
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { }
43+
44+
// TODO: Do this in a cleaner way
45+
// private class ClearTextTransmissionSink extends Sink instanceof CleartextTransmission::Sink { }
46+
/**
47+
* A sink for request forgery from model data.
48+
*/
49+
private class ModelsAsDataSink extends Sink {
50+
ModelsAsDataSink() { sinkNode(this, "request-url") }
51+
}
52+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @name Server-side request forgery
3+
* @description Making a network request with user-controlled data in the URL allows for request forgery attacks.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 9.1
7+
* @precision high
8+
* @id rust/request-forgery
9+
* @tags security
10+
* external/cwe/cwe-918
11+
*/
12+
13+
private import rust
14+
private import codeql.rust.dataflow.TaintTracking
15+
private import codeql.rust.dataflow.DataFlow
16+
private import codeql.rust.dataflow.FlowSink
17+
private import codeql.rust.Concepts
18+
private import codeql.rust.security.CleartextTransmissionExtensions
19+
private import codeql.rust.security.RequestForgeryExtensions
20+
21+
/**
22+
* A taint-tracking configuration for detecting request forgery vulnerabilities.
23+
*/
24+
module RequestForgeryConfig implements DataFlow::ConfigSig {
25+
predicate isSource(DataFlow::Node source) { source instanceof RequestForgery::Source }
26+
27+
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgery::Sink }
28+
29+
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof RequestForgery::Barrier }
30+
31+
predicate observeDiffInformedIncrementalMode() { any() }
32+
}
33+
34+
module RequestForgeryFlow = TaintTracking::Global<RequestForgeryConfig>;
35+
36+
import RequestForgeryFlow::PathGraph
37+
38+
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
39+
where RequestForgeryFlow::flowPath(source, sink)
40+
select sink.getNode(), source, sink, "The $@ of this request depends on a $@.", sink, "URL",
41+
source.getNode(), "user-provided value"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#select
2+
| request_forgery_tests.rs:68:24:68:35 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:68:24:68:35 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:68:24:68:35 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
3+
| request_forgery_tests.rs:68:24:68:35 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:68:24:68:35 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:68:24:68:35 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
4+
| request_forgery_tests.rs:78:25:78:36 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:78:25:78:36 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:78:25:78:36 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
5+
| request_forgery_tests.rs:82:25:82:36 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:82:25:82:36 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:82:25:82:36 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
6+
| request_forgery_tests.rs:86:25:86:36 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:86:25:86:36 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:86:25:86:36 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
7+
| request_forgery_tests.rs:92:29:92:40 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:92:29:92:40 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:92:29:92:40 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
8+
| request_forgery_tests.rs:92:29:92:40 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:92:29:92:40 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:92:29:92:40 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
9+
| request_forgery_tests.rs:98:37:98:48 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:98:37:98:48 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:98:37:98:48 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
10+
| request_forgery_tests.rs:98:37:98:48 | ...::get | request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:98:37:98:48 | ...::get | The $@ of this request depends on a $@. | request_forgery_tests.rs:98:37:98:48 | ...::get | URL | request_forgery_tests.rs:65:29:65:36 | user_url | user-provided value |
11+
edges
12+
| request_forgery_tests.rs:64:5:64:14 | res | request_forgery_tests.rs:77:27:77:49 | { ... } | provenance | |
13+
| request_forgery_tests.rs:64:5:64:14 | res | request_forgery_tests.rs:81:27:81:57 | { ... } | provenance | |
14+
| request_forgery_tests.rs:64:5:64:14 | res | request_forgery_tests.rs:85:27:85:70 | { ... } | provenance | |
15+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:68:38:68:45 | user_url | provenance | |
16+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:68:38:68:45 | user_url | provenance | |
17+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:77:27:77:49 | MacroExpr | provenance | |
18+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:81:27:81:57 | MacroExpr | provenance | |
19+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:85:27:85:70 | MacroExpr | provenance | |
20+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:92:43:92:50 | user_url | provenance | |
21+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:92:43:92:50 | user_url | provenance | |
22+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:98:51:98:58 | user_url | provenance | |
23+
| request_forgery_tests.rs:65:29:65:36 | user_url | request_forgery_tests.rs:98:51:98:58 | user_url | provenance | |
24+
| request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | request_forgery_tests.rs:68:24:68:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
25+
| request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | request_forgery_tests.rs:68:24:68:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
26+
| request_forgery_tests.rs:68:38:68:45 | user_url | request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | provenance | |
27+
| request_forgery_tests.rs:68:38:68:45 | user_url | request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | provenance | |
28+
| request_forgery_tests.rs:77:13:77:15 | url | request_forgery_tests.rs:78:39:78:41 | url | provenance | |
29+
| request_forgery_tests.rs:77:27:77:49 | ...::format(...) | request_forgery_tests.rs:64:5:64:14 | res | provenance | |
30+
| request_forgery_tests.rs:77:27:77:49 | ...::must_use(...) | request_forgery_tests.rs:77:13:77:15 | url | provenance | |
31+
| request_forgery_tests.rs:77:27:77:49 | MacroExpr | request_forgery_tests.rs:77:27:77:49 | ...::format(...) | provenance | MaD:291 |
32+
| request_forgery_tests.rs:77:27:77:49 | { ... } | request_forgery_tests.rs:77:27:77:49 | ...::must_use(...) | provenance | MaD:10629 |
33+
| request_forgery_tests.rs:78:38:78:41 | &url [&ref] | request_forgery_tests.rs:78:25:78:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
34+
| request_forgery_tests.rs:78:39:78:41 | url | request_forgery_tests.rs:78:38:78:41 | &url [&ref] | provenance | |
35+
| request_forgery_tests.rs:81:13:81:15 | url | request_forgery_tests.rs:82:39:82:41 | url | provenance | |
36+
| request_forgery_tests.rs:81:27:81:57 | ...::format(...) | request_forgery_tests.rs:64:5:64:14 | res | provenance | |
37+
| request_forgery_tests.rs:81:27:81:57 | ...::must_use(...) | request_forgery_tests.rs:81:13:81:15 | url | provenance | |
38+
| request_forgery_tests.rs:81:27:81:57 | MacroExpr | request_forgery_tests.rs:81:27:81:57 | ...::format(...) | provenance | MaD:291 |
39+
| request_forgery_tests.rs:81:27:81:57 | { ... } | request_forgery_tests.rs:81:27:81:57 | ...::must_use(...) | provenance | MaD:10629 |
40+
| request_forgery_tests.rs:82:38:82:41 | &url [&ref] | request_forgery_tests.rs:82:25:82:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
41+
| request_forgery_tests.rs:82:39:82:41 | url | request_forgery_tests.rs:82:38:82:41 | &url [&ref] | provenance | |
42+
| request_forgery_tests.rs:85:13:85:15 | url | request_forgery_tests.rs:86:39:86:41 | url | provenance | |
43+
| request_forgery_tests.rs:85:27:85:70 | ...::format(...) | request_forgery_tests.rs:64:5:64:14 | res | provenance | |
44+
| request_forgery_tests.rs:85:27:85:70 | ...::must_use(...) | request_forgery_tests.rs:85:13:85:15 | url | provenance | |
45+
| request_forgery_tests.rs:85:27:85:70 | MacroExpr | request_forgery_tests.rs:85:27:85:70 | ...::format(...) | provenance | MaD:291 |
46+
| request_forgery_tests.rs:85:27:85:70 | { ... } | request_forgery_tests.rs:85:27:85:70 | ...::must_use(...) | provenance | MaD:10629 |
47+
| request_forgery_tests.rs:86:38:86:41 | &url [&ref] | request_forgery_tests.rs:86:25:86:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
48+
| request_forgery_tests.rs:86:39:86:41 | url | request_forgery_tests.rs:86:38:86:41 | &url [&ref] | provenance | |
49+
| request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | request_forgery_tests.rs:92:29:92:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
50+
| request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | request_forgery_tests.rs:92:29:92:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
51+
| request_forgery_tests.rs:92:43:92:50 | user_url | request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | provenance | |
52+
| request_forgery_tests.rs:92:43:92:50 | user_url | request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | provenance | |
53+
| request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | request_forgery_tests.rs:98:37:98:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
54+
| request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | request_forgery_tests.rs:98:37:98:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
55+
| request_forgery_tests.rs:98:51:98:58 | user_url | request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | provenance | |
56+
| request_forgery_tests.rs:98:51:98:58 | user_url | request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | provenance | |
57+
nodes
58+
| request_forgery_tests.rs:64:5:64:14 | res | semmle.label | res |
59+
| request_forgery_tests.rs:64:5:64:14 | res | semmle.label | res |
60+
| request_forgery_tests.rs:64:5:64:14 | res | semmle.label | res |
61+
| request_forgery_tests.rs:65:29:65:36 | user_url | semmle.label | user_url |
62+
| request_forgery_tests.rs:65:29:65:36 | user_url | semmle.label | user_url |
63+
| request_forgery_tests.rs:68:24:68:35 | ...::get | semmle.label | ...::get |
64+
| request_forgery_tests.rs:68:24:68:35 | ...::get | semmle.label | ...::get |
65+
| request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
66+
| request_forgery_tests.rs:68:37:68:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
67+
| request_forgery_tests.rs:68:38:68:45 | user_url | semmle.label | user_url |
68+
| request_forgery_tests.rs:68:38:68:45 | user_url | semmle.label | user_url |
69+
| request_forgery_tests.rs:77:13:77:15 | url | semmle.label | url |
70+
| request_forgery_tests.rs:77:27:77:49 | ...::format(...) | semmle.label | ...::format(...) |
71+
| request_forgery_tests.rs:77:27:77:49 | ...::must_use(...) | semmle.label | ...::must_use(...) |
72+
| request_forgery_tests.rs:77:27:77:49 | MacroExpr | semmle.label | MacroExpr |
73+
| request_forgery_tests.rs:77:27:77:49 | { ... } | semmle.label | { ... } |
74+
| request_forgery_tests.rs:78:25:78:36 | ...::get | semmle.label | ...::get |
75+
| request_forgery_tests.rs:78:38:78:41 | &url [&ref] | semmle.label | &url [&ref] |
76+
| request_forgery_tests.rs:78:39:78:41 | url | semmle.label | url |
77+
| request_forgery_tests.rs:81:13:81:15 | url | semmle.label | url |
78+
| request_forgery_tests.rs:81:27:81:57 | ...::format(...) | semmle.label | ...::format(...) |
79+
| request_forgery_tests.rs:81:27:81:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
80+
| request_forgery_tests.rs:81:27:81:57 | MacroExpr | semmle.label | MacroExpr |
81+
| request_forgery_tests.rs:81:27:81:57 | { ... } | semmle.label | { ... } |
82+
| request_forgery_tests.rs:82:25:82:36 | ...::get | semmle.label | ...::get |
83+
| request_forgery_tests.rs:82:38:82:41 | &url [&ref] | semmle.label | &url [&ref] |
84+
| request_forgery_tests.rs:82:39:82:41 | url | semmle.label | url |
85+
| request_forgery_tests.rs:85:13:85:15 | url | semmle.label | url |
86+
| request_forgery_tests.rs:85:27:85:70 | ...::format(...) | semmle.label | ...::format(...) |
87+
| request_forgery_tests.rs:85:27:85:70 | ...::must_use(...) | semmle.label | ...::must_use(...) |
88+
| request_forgery_tests.rs:85:27:85:70 | MacroExpr | semmle.label | MacroExpr |
89+
| request_forgery_tests.rs:85:27:85:70 | { ... } | semmle.label | { ... } |
90+
| request_forgery_tests.rs:86:25:86:36 | ...::get | semmle.label | ...::get |
91+
| request_forgery_tests.rs:86:38:86:41 | &url [&ref] | semmle.label | &url [&ref] |
92+
| request_forgery_tests.rs:86:39:86:41 | url | semmle.label | url |
93+
| request_forgery_tests.rs:92:29:92:40 | ...::get | semmle.label | ...::get |
94+
| request_forgery_tests.rs:92:29:92:40 | ...::get | semmle.label | ...::get |
95+
| request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
96+
| request_forgery_tests.rs:92:42:92:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
97+
| request_forgery_tests.rs:92:43:92:50 | user_url | semmle.label | user_url |
98+
| request_forgery_tests.rs:92:43:92:50 | user_url | semmle.label | user_url |
99+
| request_forgery_tests.rs:98:37:98:48 | ...::get | semmle.label | ...::get |
100+
| request_forgery_tests.rs:98:37:98:48 | ...::get | semmle.label | ...::get |
101+
| request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
102+
| request_forgery_tests.rs:98:50:98:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
103+
| request_forgery_tests.rs:98:51:98:58 | user_url | semmle.label | user_url |
104+
| request_forgery_tests.rs:98:51:98:58 | user_url | semmle.label | user_url |
105+
subpaths
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
query: queries/security/CWE-918/RequestForgery.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql

0 commit comments

Comments
 (0)