🔒 Fix path traversal vulnerability in /export/temp/ endpoint (#17656)

The /export/temp/ endpoint used c.Request.URL.Path directly in
filepath.Join without any validation, allowing path traversal via
sequences like /export/temp/../../ to access files outside the
intended temp directory.

This fix:
- Constrains file access to {TempDir}/export/temp/ base directory
- Cleans the relative path with filepath.Clean
- Rejects paths containing ".."
- Validates the final path with IsSubPath check

Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Qiaochu Hu
2026-05-10 19:01:32 +08:00
committed by GitHub
parent bb55695925
commit b763d787d1

View File

@@ -304,10 +304,21 @@ func serveExport(ginServer *gin.Engine) {
exportGroup := ginServer.Group("/export/", model.CheckAuth)
exportBaseDir := filepath.Join(util.TempDir, "export")
// 应下载而不是查看导出的文件
exportGroup.GET("/*filepath", func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.Path, "/export/temp/") {
c.File(filepath.Join(util.TempDir, c.Request.URL.Path))
tempBaseDir := filepath.Join(util.TempDir, "export", "temp")
relativePath := strings.TrimPrefix(c.Request.URL.Path, "/export/temp/")
relativePath = filepath.Clean(relativePath)
if strings.Contains(relativePath, "..") {
c.Status(http.StatusUnauthorized)
return
}
fullPath := filepath.Join(tempBaseDir, relativePath)
if !gulu.File.IsSubPath(tempBaseDir, fullPath) {
c.Status(http.StatusUnauthorized)
return
}
c.File(fullPath)
return
}