Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions 3rdparty/libzipplugin/libzipplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,8 +761,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("../", "");
}
Expand Down Expand Up @@ -860,6 +860,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()) &&
Comment on lines +864 to +866
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The path containment check can reject valid extractions when the target is the filesystem root.

When options.strTargetPath is the filesystem root (e.g. "/"), cleanTargetPath remains "/", so the check becomes cleanDestPath.startsWith("//"). A path like "/tmp/file" will fail both this and the equality check, and be incorrectly rejected even though it is under the intended root. If targeting the root directory is supported, you’ll need to special-case cleanTargetPath == QDir::rootPath() or otherwise adjust the prefix logic to correctly handle root paths.

cleanDestPath != cleanTargetPath) {
qInfo() << "Path traversal detected! Rejected path: " << strFileName;
return ET_FileWriteError;
}

QFile file(strDestFileName);

// Store parent mtime.
Expand Down