diff --git a/crates/bin/docs_rs_web/src/middleware/security.rs b/crates/bin/docs_rs_web/src/middleware/security.rs index 13d1284aa..d2e76484c 100644 --- a/crates/bin/docs_rs_web/src/middleware/security.rs +++ b/crates/bin/docs_rs_web/src/middleware/security.rs @@ -41,7 +41,12 @@ fn validate_path(initial_path: &str) -> Result<()> { } fn validate_decoded_path(path: &str) -> Result<()> { - if path.contains("/../") || path.ends_with("/..") { + if path.contains("/../") + || path.ends_with("/..") + || path.contains("//\\../") + || path.contains("\\..\\") + || path.ends_with("\\..") + { bail!("path traversal attempt"); } @@ -61,6 +66,7 @@ mod tests { testing::{AxumResponseTestExt as _, AxumRouterTestExt as _}, }; use axum::{Router, middleware, routing::get}; + use test_case::test_case; use tower::ServiceBuilder; @@ -78,6 +84,18 @@ mod tests { #[test_case( "/crate/mika-cli/latest/source/..%25c1%259c..%25c1%259c..%25c1%259c..%25c1%259c..%25c1%259c..%25c1%259c..%25c1%259c..%25c1%259c/etc/passwd" )] + #[test_case( + "/crate/aether/latest/source/compiler/node_modules/@richardanaya//%5c../%5c../%5c../%5c../%5c../%5c../%5c../etc/passwd"; + "with backslash" + )] + #[test_case( + "/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%5cwindows/win.ini"; + "double backslash" + )] + #[test_case( + "/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" + )] async fn test_invalid_path(path: &str) -> Result<()> { let app = Router::new() .route("/{*inner}", get(|| async { StatusCode::OK }))