CVE-2026-22257
Salvo is vulnerable to stored XSS in the list_html function by uploading files with malicious names
Salvo is a Rust web backend framework. Prior to version 0.88.1, the function list_html generates a file view of a folder without sanitizing the files or folders names, this may potentially lead to XSS in cases where a website allow the access to public files using this feature and anyone can upload a file. This issue has been patched in version 0.88.1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- High
- Integrity
- Low
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
8.8
Salvo is vulnerable to stored XSS in the list_html function by uploading files with malicious names
Salvo is a Rust web backend framework. Prior to version 0.88.1, the function list_html generates a file view of a folder without sanitizing the files or folders names, this may potentially lead to XSS in cases where a website allow the access to public files using this feature and anyone can upload a file. This issue has been patched in version 0.88.1.
- Record
CVE-2026-22257- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Weakness
- CWE-79
- Updated
- 2026-11-02
EUVDEUVD-2026-1423
8.8
Salvo is a Rust web backend framework. Prior to version 0.88.1, the function list_html generates a file view of a folder without sanitizing the files or folders names, this may potentially lead to XSS in cases where a website allow the access to public files using this feature and anyone can upload a file. This issue has been patched in version 0.88.1.
- Record
EUVD-2026-1423- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-54m3-5fxr-2f3j
8.8
Salvo is vulnerable to stored XSS in the list_html function by uploading files with malicious names
Summary
The function list_html generates a file view of a folder without sanitizing the files or folders names, potentially leading to XSS in cases where a website allows access to public files using this feature, allowing anyone to upload a file.
Details
The vulnerable snippet of code is the following: dir.rs
// ... fn list_html(...
let mut link = "".to_owned();
format!(
r#"<a href="/">{}</a>{}"#,
HOME_ICON,
segments
.map(|seg| {
link = format!("{link}/{seg}");
format!("/<a href=\"{link}\">{seg}</a>")
})
.collect::<Vec<_>>()
.join("")
)
// ...
PoC
https://github.com/user-attachments/assets/1e161e17-f033-4cc4-855b-43fd38ed1be4
Here is the example app we used:
mian.rs
use salvo::prelude::*;
use salvo::serve_static::StaticDir;
use std::path::PathBuf;
use tokio::fs;
const INDEX_HTML: &str = r#"<!doctype html>
<html>
<head><meta charset="utf-8"><title>StaticDir PoC</title></head>
<body>
<h2>Upload a file</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>
<p>Browse uploads:</p>
<ul>
<li><a href="/files">/files</a></li>
<li><a href="/files/">/files/</a></li>
</ul>
</body>
</html>
"#;
#[handler]
async fn index(res: &mut Response) {
res.render(Text::Html(INDEX_HTML));
}
#[handler]
async fn upload(req: &mut Request, res: &mut Response) {
fs::create_dir_all("uploads").await.expect("create uploads dir");
let form = match req.form_data().await {
Ok(v) => v,
Err(e) => {
res.status_code(StatusCode::BAD_REQUEST);
res.render(Text::Plain(format!("form_data parse failed: {e}")));
return;
}
};
let Some(file_part) = form.files.get("file") else {
res.status_code(StatusCode::BAD_REQUEST);
res.render(Text::Plain("missing file field (name=\"file\")"));
return;
};
let original_name = file_part.name().unwrap_or("upload.bin");
let mut dest = PathBuf::from("uploads");
dest.push(original_name);
let tmp_path = file_part.path();
if let Err(e) = fs::copy(tmp_path, &dest).await {
res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
res.render(Text::Plain(format!("save failed: {e}")));
return;
}
res.render(Text::Plain(format!(
"Uploaded as: {original_name}\nNow open: http://127.0.0.1:5800/files/\n"
)));
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();
fs::create_dir_all("uploads").await.expect("create uploads dir");
let router = Router::new()
.get(index)
.push(Router::with_path("upload").post(upload))
.push(
Router::with_path("files/{**rest_path}")
.get(StaticDir::new("uploads").auto_list(true)),
);
let acceptor = TcpListener::new("127.0.0.1:5800").bind().await;
Server::new(acceptor).serve(router).await;
}
Cargo.toml
[package]
name = "poc"
version = "0.1.0"
edition = "2024"
[dependencies]
salvo = { version = "0.85.0", features = ["serve-static"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
tracing-subscriber = "0.3"
Impact
JavaScript execution, most likely leading to an account takeover, depending on the site's constraint (CSP, etc…).
- Record
GHSA-54m3-5fxr-2f3j- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Weakness
- CWE-79
- Updated
- 2026-11-02
NVD
8.8
Salvo is a Rust web backend framework. Prior to version 0.88.1, the function list_html generates a file view of a folder without sanitizing the files or folders names, this may potentially lead to XSS in cases where a website allow the access to public files using this feature and anyone can upload a file. This issue has been patched in version 0.88.1.
- Record
CVE-2026-22257- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Weakness
- CWE-79
- Updated
- 2026-11-02
OSV
8.8
Salvo is vulnerable to stored XSS in the list_html function by uploading files with malicious names
Salvo is a Rust web backend framework. Prior to version 0.88.1, the function list_html generates a file view of a folder without sanitizing the files or folders names, this may potentially lead to XSS in cases where a website allow the access to public files using this feature and anyone can upload a file. This issue has been patched in version 0.88.1.
- Record
CVE-2026-22257- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Weakness
- CWE-79
- Updated
- 2026-11-02
OSVGHSA-54m3-5fxr-2f3j
8.8
Salvo is vulnerable to stored XSS in the list_html function by uploading files with malicious names
Summary
The function list_html generates a file view of a folder without sanitizing the files or folders names, potentially leading to XSS in cases where a website allows access to public files using this feature, allowing anyone to upload a file.
Details
The vulnerable snippet of code is the following: dir.rs
// ... fn list_html(...
let mut link = "".to_owned();
format!(
r#"<a href="/">{}</a>{}"#,
HOME_ICON,
segments
.map(|seg| {
link = format!("{link}/{seg}");
format!("/<a href=\"{link}\">{seg}</a>")
})
.collect::<Vec<_>>()
.join("")
)
// ...
PoC
https://github.com/user-attachments/assets/1e161e17-f033-4cc4-855b-43fd38ed1be4
Here is the example app we used:
mian.rs
use salvo::prelude::*;
use salvo::serve_static::StaticDir;
use std::path::PathBuf;
use tokio::fs;
const INDEX_HTML: &str = r#"<!doctype html>
<html>
<head><meta charset="utf-8"><title>StaticDir PoC</title></head>
<body>
<h2>Upload a file</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>
<p>Browse uploads:</p>
<ul>
<li><a href="/files">/files</a></li>
<li><a href="/files/">/files/</a></li>
</ul>
</body>
</html>
"#;
#[handler]
async fn index(res: &mut Response) {
res.render(Text::Html(INDEX_HTML));
}
#[handler]
async fn upload(req: &mut Request, res: &mut Response) {
fs::create_dir_all("uploads").await.expect("create uploads dir");
let form = match req.form_data().await {
Ok(v) => v,
Err(e) => {
res.status_code(StatusCode::BAD_REQUEST);
res.render(Text::Plain(format!("form_data parse failed: {e}")));
return;
}
};
let Some(file_part) = form.files.get("file") else {
res.status_code(StatusCode::BAD_REQUEST);
res.render(Text::Plain("missing file field (name=\"file\")"));
return;
};
let original_name = file_part.name().unwrap_or("upload.bin");
let mut dest = PathBuf::from("uploads");
dest.push(original_name);
let tmp_path = file_part.path();
if let Err(e) = fs::copy(tmp_path, &dest).await {
res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
res.render(Text::Plain(format!("save failed: {e}")));
return;
}
res.render(Text::Plain(format!(
"Uploaded as: {original_name}\nNow open: http://127.0.0.1:5800/files/\n"
)));
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();
fs::create_dir_all("uploads").await.expect("create uploads dir");
let router = Router::new()
.get(index)
.push(Router::with_path("upload").post(upload))
.push(
Router::with_path("files/{**rest_path}")
.get(StaticDir::new("uploads").auto_list(true)),
);
let acceptor = TcpListener::new("127.0.0.1:5800").bind().await;
Server::new(acceptor).serve(router).await;
}
Cargo.toml
[package]
name = "poc"
version = "0.1.0"
edition = "2024"
[dependencies]
salvo = { version = "0.85.0", features = ["serve-static"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "fs"] }
tracing-subscriber = "0.3"
Impact
JavaScript execution, most likely leading to an account takeover, depending on the site's constraint (CSP, etc…).
- Record
GHSA-54m3-5fxr-2f3j- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L - Weakness
- CWE-79
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
salvocrates.io |
before 0.88.1 | 0.88.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-22257 is a high vulnerability (CVSS 8.8) in Salvo, published January 8, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.33%, the 26th percentile. Fixed in salvo 0.88.1.
References
github.com/salvo-rs/salvo/security/advisories/GHSA-54m3-5fxr-2f3j
github.com/salvo-rs/salvo/blob/16efeba312a274739606ce76366d921768628654/crates/serve-static/src/dir.rs
nvd.nist.gov/vuln/detail/CVE-2026-22257
github.com/advisories/GHSA-54m3-5fxr-2f3j
github.com/CVEProject/cvelistV5/tree/main/cves/2026/22xxx/CVE-2026-22257.json
github.com/salvo-rs/salvo