fix(wcp): normalize separators before traversal check on unpack

Older WCP files packed on Windows (before pack-side normalization
was added) carry backslash separators. Normalize to '/' first so
the unpack works on any platform — and so the traversal check sees
a consistent canonical form (no more '\' special case).
This commit is contained in:
Kelsi 2026-05-06 07:54:54 -07:00
parent 439d1381f0
commit 45dabaff44

View file

@ -181,6 +181,12 @@ bool ContentPacker::unpackZone(const std::string& wcpPath, const std::string& de
}
std::string path(pathLen, '\0');
in.read(path.data(), pathLen);
// Normalize separators in case this WCP was packed before the
// pack-side normalization was added (older builds emitted '\' on
// Windows). Backslash translation must happen BEFORE the
// traversal check so the absolute-path rule catches Windows
// drive letters consistently.
std::replace(path.begin(), path.end(), '\\', '/');
uint32_t dataSize;
in.read(reinterpret_cast<char*>(&dataSize), 4);
@ -192,9 +198,9 @@ bool ContentPacker::unpackZone(const std::string& wcpPath, const std::string& de
}
// Reject path-traversal attempts. Files like "../../etc/passwd" would
// write outside destDir/<zoneName>/ and clobber system files.
// Also catch Windows-style backslash traversal and absolute paths.
// (Backslashes are already normalized to '/' above.)
if (path.find("..") != std::string::npos ||
(!path.empty() && (path[0] == '/' || path[0] == '\\')) ||
(!path.empty() && path[0] == '/') ||
(path.size() >= 2 && path[1] == ':')) { // C:\... drive prefix
LOG_ERROR("WCP rejected suspicious path: ", path);
return false;