From a40c87eeedc85414e8023aceb5a37cd46788a318 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 8 Feb 2026 06:48:38 -0600 Subject: [PATCH] [dashboard] Use resolve/relative_to for download path validation Replace string-based path sanitization (.replace/.lstrip) with Path.resolve() and relative_to() validation, matching the pattern used by other dashboard endpoints (e.g. settings.rel_path). The previous approach was not exploitable but was inconsistent with the rest of the codebase. --- esphome/dashboard/web_server.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index da50279864..24a0bacf05 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -1057,14 +1057,19 @@ class DownloadBinaryRequestHandler(BaseHandler): if file_name is None: self.send_error(400) return - file_name = file_name.replace("..", "").lstrip("/") # get requested download name, or build it based on filename download_name = self.get_argument( "download", f"{storage_json.name}-{file_name}", ) - path = storage_json.firmware_bin_path.parent.joinpath(file_name) + base_dir = storage_json.firmware_bin_path.parent.resolve() + path = base_dir.joinpath(file_name).resolve() + try: + path.relative_to(base_dir) + except ValueError: + self.send_error(403) + return if not path.is_file(): args = ["esphome", "idedata", settings.rel_path(configuration)]