From dd250ca1678c0d1a058f888ea7e0319fa376c1a7 Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Thu, 4 Dec 2025 10:51:10 +0800 Subject: [PATCH] fix: Fix path traversal vulnerability in zip extraction (bug #232873) - Replace single-pass "../" removal with loop to remove all occurrences - Add final path validation to ensure extracted files stay within target directory Log: fix CITIVD Bug: https://pms.uniontech.com/bug-view-342883.html --- 3rdparty/libzipplugin/libzipplugin.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/3rdparty/libzipplugin/libzipplugin.cpp b/3rdparty/libzipplugin/libzipplugin.cpp index 19b06777..52ace67b 100644 --- a/3rdparty/libzipplugin/libzipplugin.cpp +++ b/3rdparty/libzipplugin/libzipplugin.cpp @@ -787,8 +787,8 @@ ErrorType LibzipPlugin::extractEntry(zip_t *archive, zip_int64_t index, const Ex } strFileName = m_common->trans2uft8(statBuffer.name, m_mapFileCode[index]); // 解压文件名(压缩包中) - //fix 232873 - if(strFileName.indexOf("../") != -1) { + //fix 232873 - Remove all "../" components to prevent path traversal attacks + while(strFileName.contains("../")) { qInfo() << "skipped ../ path component(s) in " << strFileName; strFileName = strFileName.replace("../", ""); } @@ -886,6 +886,15 @@ ErrorType LibzipPlugin::extractEntry(zip_t *archive, zip_int64_t index, const Ex // 解压完整文件名(含路径) QString strDestFileName = options.strTargetPath + QDir::separator() + strFileName; + // Additional security check: ensure the final path is within the target directory + QString cleanTargetPath = QDir::cleanPath(QDir(options.strTargetPath).absolutePath()); + QString cleanDestPath = QDir::cleanPath(QDir(strDestFileName).absolutePath()); + if (!cleanDestPath.startsWith(cleanTargetPath + QDir::separator()) && + cleanDestPath != cleanTargetPath) { + qInfo() << "Path traversal detected! Rejected path: " << strFileName; + return ET_FileWriteError; + } + QFile file(strDestFileName); // Store parent mtime.