{"record":{"id":"e8f783dc89e97636","repo":"jeecgboot/JeecgBoot","slug":"zip-entryname","errorCode":null,"errorMessage":"ZIP 路径穿越攻击被阻止:{entryName}","messagePattern":"ZIP 路径穿越攻击被阻止:(.+?)","errorType":"validation","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java","lineNumber":484,"sourceCode":"        String fileName = Paths.get(normalizedName).getFileName().toString();\n        return fileName.startsWith(\"._\") || fileName.equals(\".DS_Store\");\n    }\n    //update-end---author:scott ---date:2026-04-16  for：【issues/9551】macOS压缩包隐藏文件过滤-----------\n\n    /**\n     * 安全解析路径，防止Zip Slip攻击\n     *\n     * @param targetDir\n     * @param entryName\n     * @return\n     * @throws IOException\n     * @author chenrui\n     * @date 2025/4/28 16:46\n     */\n    private static Path safeResolve(Path targetDir, String entryName) throws IOException {\n        Path resolvedPath = targetDir.resolve(entryName).normalize();\n        if (!resolvedPath.startsWith(targetDir)) {\n            throw new IOException(\"ZIP 路径穿越攻击被阻止:\" + entryName);\n        }\n        return resolvedPath;\n    }\n\n    /**\n     * 复制输入流到输出流，并限制最大字节数\n     *\n     * @param in\n     * @param out\n     * @param maxBytes\n     * @return\n     * @throws IOException\n     * @author chenrui\n     * @date 2025/4/28 17:03\n     */\n    private static long copyLimited(InputStream in, OutputStream out, long maxBytes) throws IOException {\n        byte[] buffer = new byte[8192];\n        long totalCopied = 0;","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java#L466-L502","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-validate zip entries before extraction\ntry (ZipFile zf = new ZipFile(zipFile.toFile())) {\n    Path target = targetDir;\n    Enumeration<ZipArchiveEntry> entries = zf.getEntries();\n    while (entries.hasMoreElements()) {\n        String name = entries.nextElement().getName();\n        Path resolved = target.resolve(name).normalize();\n        if (!resolved.startsWith(target)) {\n            throw new JeecgBootException(\"压缩包包含非法路径条目: \" + name);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    unzipFile(zipFilePath, targetDir, callback);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"路径穿越攻击\")) {\n        log.error(\"Zip slip attack detected: {}\", e.getMessage());\n        throw new JeecgBootException(\"压缩包包含不安全的路径，已被拒绝\");\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["security","zip-slip","path-traversal","zip","rag"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}