From 719951976d23c0b847d4b70fb5b124059f2752c3 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 06:16:54 -0700 Subject: [PATCH] fix(wom+wob): reject path traversal in WOM texture paths + WOB material/group texPaths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same defensive check as the WoB doodad path guard. Texture paths from hostile WOM/WoB are passed to the asset manager; '..' or absolute paths could probe outside the assets/ tree. Now cleared on detection — slot survives but loads no texture (renderer falls back to white). Single shared rejectTraversal lambda in WoB to avoid copy-paste. --- src/pipeline/wowee_building.cpp | 11 +++++++++++ src/pipeline/wowee_model.cpp | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/pipeline/wowee_building.cpp b/src/pipeline/wowee_building.cpp index 7883e069..02f2fbdb 100644 --- a/src/pipeline/wowee_building.cpp +++ b/src/pipeline/wowee_building.cpp @@ -96,12 +96,22 @@ WoweeBuilding WoweeBuildingLoader::load(const std::string& basePath) { if (idx > vMax) idx = 0; } + // Helper: clear path on traversal/absolute attempt. + auto rejectTraversal = [](std::string& s, const char* what) { + if (s.find("..") != std::string::npos || + (!s.empty() && (s[0] == '/' || s[0] == '\\')) || + (s.size() >= 2 && s[1] == ':')) { + LOG_WARNING("WOB ", what, " path rejected (traversal): ", s); + s.clear(); + } + }; for (uint32_t ti = 0; ti < tc; ti++) { uint16_t tl; f.read(reinterpret_cast(&tl), 2); if (tl > 1024) tl = 0; std::string tp(tl, '\0'); f.read(tp.data(), tl); + rejectTraversal(tp, "group texture"); grp.texturePaths.push_back(tp); } @@ -115,6 +125,7 @@ WoweeBuilding WoweeBuildingLoader::load(const std::string& basePath) { if (pl > 1024) pl = 0; mat.texturePath.resize(pl); f.read(mat.texturePath.data(), pl); + rejectTraversal(mat.texturePath, "material texture"); f.read(reinterpret_cast(&mat.flags), 4); f.read(reinterpret_cast(&mat.shader), 4); f.read(reinterpret_cast(&mat.blendMode), 4); diff --git a/src/pipeline/wowee_model.cpp b/src/pipeline/wowee_model.cpp index 0ffee0b1..61f0e6f3 100644 --- a/src/pipeline/wowee_model.cpp +++ b/src/pipeline/wowee_model.cpp @@ -113,6 +113,14 @@ WoweeModel WoweeModelLoader::load(const std::string& basePath) { if (pathLen > 1024) { pathLen = 0; } std::string path(pathLen, '\0'); f.read(path.data(), pathLen); + // Reject path-traversal — texture paths from a hostile WOM are fed + // to the asset manager and could probe files outside assets/. + if (path.find("..") != std::string::npos || + (!path.empty() && (path[0] == '/' || path[0] == '\\')) || + (path.size() >= 2 && path[1] == ':')) { + LOG_WARNING("WOM texture path rejected (traversal): ", path); + path.clear(); + } model.texturePaths.push_back(path); }