Skip to content

Commit 52e93a4

Browse files
committed
Rust: Add XSS sink for Axum HTML response creation
1 parent d71de64 commit 52e93a4

File tree

3 files changed

+45
-2
lines changed

3 files changed

+45
-2
lines changed

rust/ql/lib/codeql/rust/security/XssExtensions.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,14 @@ module Xss {
5959
)
6060
}
6161
}
62+
63+
// TODO: Convert this to MaD once MaD supports sink for tuple struct expressions.
64+
private class AxumHtmlSink extends Sink {
65+
AxumHtmlSink() {
66+
exists(TupleStructExpr call |
67+
call.getResolvedTarget().getCanonicalPath() = "axum::response::Html" and
68+
this.asExpr() = call.getSyntacticPositionalArgument(0)
69+
)
70+
}
71+
}
6272
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
11
#select
2+
| main.rs:10:10:10:21 | html_content | main.rs:15:51:15:53 | get | main.rs:10:10:10:21 | html_content | Cross-site scripting vulnerability due to a $@. | main.rs:15:51:15:53 | get | user-provided value |
3+
| main.rs:10:10:10:21 | html_content | main.rs:15:51:15:53 | get | main.rs:10:10:10:21 | html_content | Cross-site scripting vulnerability due to a $@. | main.rs:15:51:15:53 | get | user-provided value |
24
edges
5+
| main.rs:8:24:8:36 | Query(...) [Query] | main.rs:8:30:8:35 | params | provenance | |
6+
| main.rs:8:24:8:59 | ...: Query::<...> | main.rs:9:32:9:63 | MacroExpr | provenance | |
7+
| main.rs:8:24:8:59 | ...: Query::<...> [Query] | main.rs:8:24:8:36 | Query(...) [Query] | provenance | |
8+
| main.rs:8:30:8:35 | params | main.rs:9:32:9:63 | MacroExpr | provenance | |
9+
| main.rs:9:9:9:20 | html_content | main.rs:10:10:10:21 | html_content | provenance | |
10+
| main.rs:9:32:9:63 | ...::format(...) | main.rs:9:32:9:63 | { ... } | provenance | |
11+
| main.rs:9:32:9:63 | ...::must_use(...) | main.rs:9:9:9:20 | html_content | provenance | |
12+
| main.rs:9:32:9:63 | MacroExpr | main.rs:9:32:9:63 | ...::format(...) | provenance | MaD:3 |
13+
| main.rs:9:32:9:63 | { ... } | main.rs:9:32:9:63 | ...::must_use(...) | provenance | MaD:4 |
14+
| main.rs:15:51:15:53 | get | main.rs:8:24:8:59 | ...: Query::<...> | provenance | Src:MaD:2 |
15+
| main.rs:15:51:15:53 | get | main.rs:8:24:8:59 | ...: Query::<...> [Query] | provenance | Src:MaD:1 |
16+
| main.rs:15:51:15:53 | get | main.rs:15:51:15:53 | get [Query] | provenance | Src:MaD:1 |
17+
| main.rs:15:51:15:53 | get [Query] | main.rs:8:24:8:59 | ...: Query::<...> [Query] | provenance | |
18+
models
19+
| 1 | Source: axum::routing::method_routing::get; Argument[0].Parameter[0..7].Field[axum::extract::query::Query(0)]; remote |
20+
| 2 | Source: axum::routing::method_routing::get; Argument[0].Parameter[0..7]; remote |
21+
| 3 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
22+
| 4 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
323
nodes
24+
| main.rs:8:24:8:36 | Query(...) [Query] | semmle.label | Query(...) [Query] |
25+
| main.rs:8:24:8:59 | ...: Query::<...> | semmle.label | ...: Query::<...> |
26+
| main.rs:8:24:8:59 | ...: Query::<...> [Query] | semmle.label | ...: Query::<...> [Query] |
27+
| main.rs:8:30:8:35 | params | semmle.label | params |
28+
| main.rs:9:9:9:20 | html_content | semmle.label | html_content |
29+
| main.rs:9:32:9:63 | ...::format(...) | semmle.label | ...::format(...) |
30+
| main.rs:9:32:9:63 | ...::must_use(...) | semmle.label | ...::must_use(...) |
31+
| main.rs:9:32:9:63 | MacroExpr | semmle.label | MacroExpr |
32+
| main.rs:9:32:9:63 | { ... } | semmle.label | { ... } |
33+
| main.rs:10:10:10:21 | html_content | semmle.label | html_content |
34+
| main.rs:15:51:15:53 | get | semmle.label | get |
35+
| main.rs:15:51:15:53 | get | semmle.label | get |
36+
| main.rs:15:51:15:53 | get [Query] | semmle.label | get [Query] |
437
subpaths

rust/ql/test/query-tests/security/CWE-079/axum/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ struct GreetingParams {
77

88
async fn greet_handler(Query(params): Query<GreetingParams>) -> Html<String> {
99
let html_content = format!("<p>Hello, {}!</p>", params.name);
10-
Html(html_content) // $ MISSING: Alert[rust/xss]
10+
Html(html_content) // $ Alert[rust/xss]=greet
1111
}
1212

1313
#[tokio::main]
1414
pub async fn main() {
15-
let app = Router::<()>::new().route("/greet", get(greet_handler));
15+
let app = Router::<()>::new().route("/greet", get(greet_handler)); // $ Source=greet
1616
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
1717
.await
1818
.unwrap();

0 commit comments

Comments
 (0)