From 977bb16678c93f1de003b9ef0131d1198e1e07a1 Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 29 May 2026 18:46:27 +0200 Subject: [PATCH] =?UTF-8?q?dashboard:=20format=20guard=20on=20post=5Fpurge?= =?UTF-8?q?=5Ftombstone=20(path=20traversal=20hole=20=E2=80=94=20argus=20?= =?UTF-8?q?=F0=9F=94=B4=20on=20#593)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hive-c0re/src/dashboard.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index 86fd64d2..17662b48 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -1886,6 +1886,17 @@ async fn post_purge_tombstone( State(state): State, AxumPath(name): AxumPath, ) -> Response { + // Format guard FIRST so a name like `..` can't traverse into the + // parent of `/var/lib/hyperhive/agents/{name}` and have + // `remove_dir_all` wipe `/var/lib/hyperhive/` itself. Existing + // manager + live-container checks below don't catch `..` — only + // the whitelist does. (argus #593 🔴.) Existence check via + // `containers_snapshot()` is deliberately NOT used here: + // tombstoned agents are gone from the snapshot by design; that's + // the whole point of this endpoint. + if let Some(reason) = validate_agent_name(&name) { + return (StatusCode::BAD_REQUEST, format!("bad agent name: {reason}")).into_response(); + } if name == lifecycle::MANAGER_NAME { return error_response("refusing to purge the manager's state"); }