mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 08:02:26 +00:00
fix(api): don't follow symlinks when reading service log files
Defense in depth on top of the existing `..` path-traversal check in the get_log_file handler: reject the request if the final path component is a symlink, so a planted symlink in the logs directory cannot be used to read arbitrary files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -133,7 +133,18 @@ async fn get_log_file(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let file = tokio::fs::read(format!("{}{}", *TMP_WINDMILL_LOGS_SERVICE, path)).await;
|
let full_path = format!("{}{}", *TMP_WINDMILL_LOGS_SERVICE, path);
|
||||||
|
// SECURITY (defense in depth): refuse to read through a symlink so a planted
|
||||||
|
// symlink in the logs directory cannot be used to exfiltrate arbitrary files.
|
||||||
|
// `symlink_metadata` returns the link's own metadata without following it.
|
||||||
|
match tokio::fs::symlink_metadata(&full_path).await {
|
||||||
|
Ok(meta) if meta.file_type().is_symlink() => {
|
||||||
|
return Err(Error::BadRequest("Invalid path".to_string()));
|
||||||
|
}
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => return Err(Error::NotFound(format!("File {path} not found"))),
|
||||||
|
}
|
||||||
|
let file = tokio::fs::read(&full_path).await;
|
||||||
if let Ok(bytes) = file {
|
if let Ok(bytes) = file {
|
||||||
Ok(content_plain(Body::from(bytes::Bytes::from(bytes))))
|
Ok(content_plain(Body::from(bytes::Bytes::from(bytes))))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user