Rust: Add XSS sinks for Actix and Warp

This commit is contained in:
Simon Friis Vindum
2025-11-24 15:41:17 +01:00
parent ae9c753371
commit 9e2bf76a7f
6 changed files with 66 additions and 5 deletions

View File

@@ -6,6 +6,11 @@ extensions:
- ["<actix_web::route::Route>::to", "Argument[0].Parameter[0..7]", "remote", "manual"]
# Actix attributes such as `get` expand to this `to` call on the handler.
- ["<actix_web::resource::Resource>::to", "Argument[0].Parameter[0..7]", "remote", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["<actix_web::types::html::Html>::new", "Argument[0]", "html-injection", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: summaryModel

View File

@@ -5,4 +5,9 @@ extensions:
data:
- ["<_ as warp::filter::Filter>::then", "Argument[0].Parameter[0..7]", "remote", "manual"]
- ["<_ as warp::filter::Filter>::map", "Argument[0].Parameter[0..7]", "remote", "manual"]
- ["<_ as warp::filter::Filter>::and_then", "Argument[0].Parameter[0..7]", "remote", "manual"]
- ["<_ as warp::filter::Filter>::and_then", "Argument[0].Parameter[0..7]", "remote", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["warp::reply::html", "Argument[0]", "html-injection", "manual"]

View File

@@ -1,4 +1,32 @@
#select
| main.rs:25:5:25:13 | ...::new | main.rs:8:1:8:18 | to | main.rs:25:5:25:13 | ...::new | Cross-site scripting vulnerability due to a $@. | main.rs:8:1:8:18 | to | user-provided value |
edges
| main.rs:8:1:8:18 | to | main.rs:9:29:9:51 | ...: ...::Path::<...> | provenance | Src:MaD:2 |
| main.rs:9:29:9:51 | ...: ...::Path::<...> | main.rs:10:22:10:38 | path.into_inner() | provenance | MaD:3 |
| main.rs:10:9:10:18 | user_input | main.rs:13:9:22:18 | MacroExpr | provenance | |
| main.rs:10:22:10:38 | path.into_inner() | main.rs:10:9:10:18 | user_input | provenance | |
| main.rs:12:9:12:12 | html | main.rs:25:15:25:18 | html | provenance | |
| main.rs:13:9:22:18 | ...::format(...) | main.rs:13:9:22:18 | { ... } | provenance | |
| main.rs:13:9:22:18 | ...::must_use(...) | main.rs:12:9:12:12 | html | provenance | |
| main.rs:13:9:22:18 | MacroExpr | main.rs:13:9:22:18 | ...::format(...) | provenance | MaD:4 |
| main.rs:13:9:22:18 | { ... } | main.rs:13:9:22:18 | ...::must_use(...) | provenance | MaD:5 |
| main.rs:25:15:25:18 | html | main.rs:25:5:25:13 | ...::new | provenance | MaD:1 Sink:MaD:1 |
models
| 1 | Sink: <actix_web::types::html::Html>::new; Argument[0]; html-injection |
| 2 | Source: <actix_web::resource::Resource>::to; Argument[0].Parameter[0..7]; remote |
| 3 | Summary: <actix_web::types::path::Path>::into_inner; Argument[self]; ReturnValue; taint |
| 4 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 5 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
nodes
| main.rs:8:1:8:18 | to | semmle.label | to |
| main.rs:9:29:9:51 | ...: ...::Path::<...> | semmle.label | ...: ...::Path::<...> |
| main.rs:10:9:10:18 | user_input | semmle.label | user_input |
| main.rs:10:22:10:38 | path.into_inner() | semmle.label | path.into_inner() |
| main.rs:12:9:12:12 | html | semmle.label | html |
| main.rs:13:9:22:18 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:13:9:22:18 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:13:9:22:18 | MacroExpr | semmle.label | MacroExpr |
| main.rs:13:9:22:18 | { ... } | semmle.label | { ... } |
| main.rs:25:5:25:13 | ...::new | semmle.label | ...::new |
| main.rs:25:15:25:18 | html | semmle.label | html |
subpaths

View File

@@ -5,7 +5,7 @@ use actix_web::{
};
// The "bad" example from the qldoc
#[get("/bad/{a}")]
#[get("/bad/{a}")] // $ Source
async fn vulnerable_handler(path: web::Path<String>) -> impl Responder {
let user_input = path.into_inner();
@@ -22,7 +22,7 @@ async fn vulnerable_handler(path: web::Path<String>) -> impl Responder {
user_input
);
Html::new(html) // $ MISSING: Alert[rust/xss]
Html::new(html) // $ Alert[rust/xss]
}
fn html_escape(s: &str) -> String {

View File

@@ -1,4 +1,27 @@
#select
| main.rs:12:13:12:29 | ...::html | main.rs:9:10:9:12 | map | main.rs:12:13:12:29 | ...::html | Cross-site scripting vulnerability due to a $@. | main.rs:9:10:9:12 | map | user-provided value |
edges
| main.rs:9:10:9:12 | map | main.rs:9:15:9:26 | ...: String | provenance | Src:MaD:2 |
| main.rs:9:15:9:26 | ...: String | main.rs:11:32:11:56 | MacroExpr | provenance | |
| main.rs:11:17:11:20 | body | main.rs:12:31:12:34 | body | provenance | |
| main.rs:11:32:11:56 | ...::format(...) | main.rs:11:32:11:56 | { ... } | provenance | |
| main.rs:11:32:11:56 | ...::must_use(...) | main.rs:11:17:11:20 | body | provenance | |
| main.rs:11:32:11:56 | MacroExpr | main.rs:11:32:11:56 | ...::format(...) | provenance | MaD:3 |
| main.rs:11:32:11:56 | { ... } | main.rs:11:32:11:56 | ...::must_use(...) | provenance | MaD:4 |
| main.rs:12:31:12:34 | body | main.rs:12:13:12:29 | ...::html | provenance | MaD:1 Sink:MaD:1 |
models
| 1 | Sink: warp::reply::html; Argument[0]; html-injection |
| 2 | Source: <_ as warp::filter::Filter>::map; Argument[0].Parameter[0..7]; remote |
| 3 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
| 4 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
nodes
| main.rs:9:10:9:12 | map | semmle.label | map |
| main.rs:9:15:9:26 | ...: String | semmle.label | ...: String |
| main.rs:11:17:11:20 | body | semmle.label | body |
| main.rs:11:32:11:56 | ...::format(...) | semmle.label | ...::format(...) |
| main.rs:11:32:11:56 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| main.rs:11:32:11:56 | MacroExpr | semmle.label | MacroExpr |
| main.rs:11:32:11:56 | { ... } | semmle.label | { ... } |
| main.rs:12:13:12:29 | ...::html | semmle.label | ...::html |
| main.rs:12:31:12:34 | body | semmle.label | body |
subpaths

View File

@@ -6,10 +6,10 @@ use warp::Filter;
pub async fn main() {
let hello = warp::path("greet")
.and(warp::path::param())
.map(|name: String| {
.map(|name: String| { // $ Source
// Vulnerable to XSS because it directly includes user input in the response
let body = format!("<h1>Hello, {name}!</h1>");
warp::reply::html(body) // $ MISSING: Alert[rust/xss]
warp::reply::html(body) // $ Alert[rust/xss]
});
// Start the web server on port 3000