From d6ddf1852a54e17c5498d179781f4a2734e85e88 Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Sat, 7 Mar 2026 00:34:15 -0800 Subject: [PATCH 1/2] fix: sd-server uses lora_model_dir correctly Pass ctx_params.lora_model_dir instead of "" for /v1/images/generations and /v1/images/edits handlers. The empty string caused extract_and_remove_lora() to return immediately. --- examples/server/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server/main.cpp b/examples/server/main.cpp index cc9e66cc8..c55cb2b96 100644 --- a/examples/server/main.cpp +++ b/examples/server/main.cpp @@ -476,7 +476,7 @@ int main(int argc, const char** argv) { if (gen_params.sample_params.sample_steps > 100) gen_params.sample_params.sample_steps = 100; - if (!gen_params.process_and_check(IMG_GEN, "")) { + if (!gen_params.process_and_check(IMG_GEN, ctx_params.lora_model_dir)) { res.status = 400; res.set_content(R"({"error":"invalid params"})", "application/json"); return; @@ -663,7 +663,7 @@ int main(int argc, const char** argv) { if (gen_params.sample_params.sample_steps > 100) gen_params.sample_params.sample_steps = 100; - if (!gen_params.process_and_check(IMG_GEN, "")) { + if (!gen_params.process_and_check(IMG_GEN, ctx_params.lora_model_dir)) { res.status = 400; res.set_content(R"({"error":"invalid params"})", "application/json"); return; From 2fee456469f477bac128f3625ad3db7ad8c33001 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 15 Mar 2026 04:37:11 +0000 Subject: [PATCH 2/2] fix: sanitize lora paths to prevent directory traversal Reject absolute paths in user-supplied lora references and validate that resolved relative paths stay within lora_model_dir using fs::canonical(). This prevents path traversal attacks like or from reading arbitrary files on the host. https://claude.ai/code/session_01RnNL2d3tAHW4pNuBDu3wi8 --- examples/common/common.hpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/examples/common/common.hpp b/examples/common/common.hpp index 9c50c1595..0f7ad04a9 100644 --- a/examples/common/common.hpp +++ b/examples/common/common.hpp @@ -1657,12 +1657,18 @@ struct SDGenerationParams { is_high_noise = true; } - fs::path final_path; + // Security: reject absolute paths from user input to prevent + // arbitrary file access. if (is_absolute_path(raw_path)) { - final_path = raw_path; - } else { - final_path = fs::path(lora_model_dir) / raw_path; + LOG_WARN("lora path must be relative: %s", raw_path.c_str()); + tmp = m.suffix().str(); + prompt = std::regex_replace(prompt, re, "", std::regex_constants::format_first_only); + continue; } + + // Resolve relative to the configured lora directory. + fs::path final_path = fs::path(lora_model_dir) / raw_path; + if (!fs::exists(final_path)) { bool found = false; for (const auto& ext : valid_ext) { @@ -1682,7 +1688,19 @@ struct SDGenerationParams { } } - const std::string key = final_path.lexically_normal().string(); + // Security: ensure the resolved path is within lora_model_dir + // to prevent path traversal (e.g. "../../etc/passwd"). + const fs::path canon_dir = fs::canonical(lora_model_dir); + const fs::path canon_path = fs::canonical(final_path); + const std::string dir_str = canon_dir.string() + std::string(1, fs::path::preferred_separator); + if (canon_path.string().rfind(dir_str, 0) != 0 && canon_path != canon_dir) { + LOG_WARN("lora path escapes lora_model_dir: %s", raw_path.c_str()); + tmp = m.suffix().str(); + prompt = std::regex_replace(prompt, re, "", std::regex_constants::format_first_only); + continue; + } + + const std::string key = canon_path.string(); if (is_high_noise) high_noise_lora_map[key] += mul;