jeecgboot/JeecgBoot · critical · IOException
ZIP 路径穿越攻击被阻止:{entryName}
Error message
ZIP 路径穿越攻击被阻止:{entryName} What it means
Thrown by AiragKnowledgeDocServiceImpl.safeResolve() when a zip entry name resolves to a path outside the target extraction directory. The method resolves entryName against targetDir, normalizes the result, and verifies it still starts with targetDir. This is the classic Zip-Slip vulnerability defense.
Source
Thrown at jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java:484
String fileName = Paths.get(normalizedName).getFileName().toString();
return fileName.startsWith("._") || fileName.equals(".DS_Store");
}
//update-end---author:scott ---date:2026-04-16 for:【issues/9551】macOS压缩包隐藏文件过滤-----------
/**
* 安全解析路径,防止Zip Slip攻击
*
* @param targetDir
* @param entryName
* @return
* @throws IOException
* @author chenrui
* @date 2025/4/28 16:46
*/
private static Path safeResolve(Path targetDir, String entryName) throws IOException {
Path resolvedPath = targetDir.resolve(entryName).normalize();
if (!resolvedPath.startsWith(targetDir)) {
throw new IOException("ZIP 路径穿越攻击被阻止:" + entryName);
}
return resolvedPath;
}
/**
* 复制输入流到输出流,并限制最大字节数
*
* @param in
* @param out
* @param maxBytes
* @return
* @throws IOException
* @author chenrui
* @date 2025/4/28 17:03
*/
private static long copyLimited(InputStream in, OutputStream out, long maxBytes) throws IOException {
byte[] buffer = new byte[8192];
long totalCopied = 0;View on GitHub (pinned to 96fb33f5ec)
Solutions
- Re-create the zip archive ensuring all entry paths are relative and do not contain '..' segments.
- Use a standard zip tool that produces clean relative paths (avoid tools that embed absolute paths).
- If processing untrusted archives is required, the current safeResolve guard already prevents exploitation — the error is the guard working as intended.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate zip entries before extraction
try (ZipFile zf = new ZipFile(zipFile.toFile())) {
Path target = targetDir;
Enumeration<ZipArchiveEntry> entries = zf.getEntries();
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
Path resolved = target.resolve(name).normalize();
if (!resolved.startsWith(target)) {
throw new JeecgBootException("压缩包包含非法路径条目: " + name);
}
}
} Try / catch
try {
unzipFile(zipFilePath, targetDir, callback);
} catch (IOException e) {
if (e.getMessage().contains("路径穿越攻击")) {
log.error("Zip slip attack detected: {}", e.getMessage());
throw new JeecgBootException("压缩包包含不安全的路径,已被拒绝");
}
throw e;
} Prevention
- Only accept archives from trusted sources.
- Create zip archives with standard tools that produce clean relative paths.
- Never trust absolute paths or '../' segments in archive entries.
- The safeResolve guard is already in place — this error means the defense worked.
When it happens
Trigger: A zip archive containing an entry with a name like '../../../etc/passwd' or '..\..\windows\system32' that, when resolved against the target directory, escapes it. The normalize() call collapses the '..' segments, and the startsWith check detects the escape.
Common situations: A maliciously crafted zip designed to overwrite system files (Zip-Slip attack); an archive created with absolute paths or entries using relative '../' segments; some older zip tools that embed full paths.
Related errors
- 文件路径包含非法字符
- 解压文件数量超限,可能是zip bomb攻击
- 解压总大小超限,可能是zip bomb攻击
- 单个文件解压超限,可能是zip bomb攻击
- Illegal access to path outside of base directory.
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/e8f783dc89e97636.
Report an issue: GitHub.