diff --git a/Cargo.lock b/Cargo.lock index 1ce176263..a5d183fd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7057,9 +7057,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.11" +version = "0.103.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20a6af516fea4b20eccceaf166e8aa666ac996208e8a644ce3ef5aa783bc7cd4" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" dependencies = [ "aws-lc-rs", "ring", diff --git a/crates/bin/docs_rs_web/src/handlers/crate_details.rs b/crates/bin/docs_rs_web/src/handlers/crate_details.rs index 6ecfad115..060642dbb 100644 --- a/crates/bin/docs_rs_web/src/handlers/crate_details.rs +++ b/crates/bin/docs_rs_web/src/handlers/crate_details.rs @@ -2227,7 +2227,7 @@ path = "src/lib.rs" .create() .await?; - let resp = env.web_app().await.get("/crate/dummy%3E").await?; + let resp = env.web_app().await.get("/crate/dummy%7B").await?; assert_eq!(resp.status(), StatusCode::BAD_REQUEST); Ok(()) diff --git a/crates/bin/docs_rs_web/src/handlers/rustdoc.rs b/crates/bin/docs_rs_web/src/handlers/rustdoc.rs index 22d9cf93e..99ee16e74 100644 --- a/crates/bin/docs_rs_web/src/handlers/rustdoc.rs +++ b/crates/bin/docs_rs_web/src/handlers/rustdoc.rs @@ -2631,12 +2631,12 @@ mod test { assert_eq!( latest_version_redirect( "tungstenite", - "/tungstenite/0.10.0/tungstenite/?search=String+-%3E+Message", + "/tungstenite/0.10.0/tungstenite/?search=String+-%7B+Message", &env.web_app().await, env.config() ) .await?, - "/crate/tungstenite/latest/target-redirect/tungstenite/?search=String+-%3E+Message", + "/crate/tungstenite/latest/target-redirect/tungstenite/?search=String+-%7B+Message", ); Ok(()) }); @@ -3388,8 +3388,8 @@ mod test { let web = env.web_app().await; web.assert_redirect_cached_unchecked( - "/minidumper/latest/%3c%2f%73%63%72%69%70%74%3e%3c%74%65%73%74%65%3e", - "/minidumper/latest/%3C/script%3E%3Cteste%3E", + "/minidumper/latest/%7d%2f%73%63%72%69%70%74%7b%7d%74%65%73%74%65%7b", + "/minidumper/latest/%7D/script%7B%7Dteste%7B", CachePolicy::ForeverInCdn(KrateName::from_str("minidumper").unwrap().into()), env.config(), ) diff --git a/crates/bin/docs_rs_web/src/middleware/security.rs b/crates/bin/docs_rs_web/src/middleware/security.rs index d2e76484c..630e670e9 100644 --- a/crates/bin/docs_rs_web/src/middleware/security.rs +++ b/crates/bin/docs_rs_web/src/middleware/security.rs @@ -55,6 +55,11 @@ fn validate_decoded_path(path: &str) -> Result<()> { bail!("detected `#` in request path"); } + // `<` and `>` are never allowed — they indicate HTML injection attempts. + if path.contains('<') || path.contains('>') { + bail!("detected `<` or `>` in request path"); + } + Ok(()) } @@ -96,6 +101,9 @@ mod tests { "/casual_logger/0.6.4/%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e"; "ends with backslash dot dot" )] + #[test_case( + "/mathru/0.10.0/i686-unknown-linux-gnu/mathru/special/hypergeometric/%3E%3Cscript%20defer%20src=%22https:/cdn.jsdelivr.net/npm/katex@0.10.1/dist/katex.min.js%22%20integrity=%22sha384-2BKqo+exmr9su6dir+qCw08N2ZKRucY4PrGQPP..." + )] async fn test_invalid_path(path: &str) -> Result<()> { let app = Router::new() .route("/{*inner}", get(|| async { StatusCode::OK }))