fix: ensure symlink inside serve root (#670)

This commit is contained in:
sigoden
2026-02-05 22:08:04 +08:00
committed by GitHub
parent db7a0530a2
commit a118c1348e

View File

@@ -272,7 +272,7 @@ impl Server {
let render_spa = self.args.render_spa; let render_spa = self.args.render_spa;
let render_try_index = self.args.render_try_index; let render_try_index = self.args.render_try_index;
if !self.args.allow_symlink && !is_miss && !self.is_root_contained(path).await { if self.guard_root_contained(path).await {
status_not_found(&mut res); status_not_found(&mut res);
return Ok(res); return Ok(res);
} }
@@ -1114,6 +1114,11 @@ impl Server {
ensure_path_parent(&dest).await?; ensure_path_parent(&dest).await?;
if self.guard_root_contained(&dest).await {
status_bad_request(res, "Invalid Destination");
return Ok(());
}
fs::copy(path, &dest).await?; fs::copy(path, &dest).await?;
status_no_content(res); status_no_content(res);
@@ -1130,6 +1135,11 @@ impl Server {
ensure_path_parent(&dest).await?; ensure_path_parent(&dest).await?;
if self.guard_root_contained(&dest).await {
status_bad_request(res, "Invalid Destination");
return Ok(());
}
fs::rename(path, &dest).await?; fs::rename(path, &dest).await?;
status_no_content(res); status_no_content(res);
@@ -1289,6 +1299,21 @@ impl Server {
Ok(()) Ok(())
} }
async fn guard_root_contained(&self, path: &Path) -> bool {
if self.args.allow_symlink {
return false;
}
let path = if !fs::try_exists(path).await.unwrap_or_default() {
match path.parent() {
Some(parent) => parent.to_path_buf(),
None => return true,
}
} else {
path.to_path_buf()
};
!self.is_root_contained(path.as_path()).await
}
async fn is_root_contained(&self, path: &Path) -> bool { async fn is_root_contained(&self, path: &Path) -> bool {
fs::canonicalize(path) fs::canonicalize(path)
.await .await