{"record":{"id":"9564b88ae55bbab5","repo":"flipped-aurora/gin-vue-admin","slug":"s-9564b8","errorCode":null,"errorMessage":"%s 文件名不合法","messagePattern":"(.+?) 文件名不合法","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/utils/zip.go","lineNumber":23,"sourceCode":"\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// 解压\nfunc Unzip(zipFile string, destDir string) ([]string, error) {\n\tzipReader, err := zip.OpenReader(zipFile)\n\tvar paths []string\n\tif err != nil {\n\t\treturn []string{}, err\n\t}\n\tdefer zipReader.Close()\n\n\tfor _, f := range zipReader.File {\n\t\tif strings.Contains(f.Name, \"..\") {\n\t\t\treturn []string{}, fmt.Errorf(\"%s 文件名不合法\", f.Name)\n\t\t}\n\t\tfpath := filepath.Join(destDir, f.Name)\n\t\tpaths = append(paths, fpath)\n\t\tif f.FileInfo().IsDir() {\n\t\t\tos.MkdirAll(fpath, os.ModePerm)\n\t\t} else {\n\t\t\tif err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {\n\t\t\t\treturn []string{}, err\n\t\t\t}\n\n\t\t\tinFile, err := f.Open()\n\t\t\tif err != nil {\n\t\t\t\treturn []string{}, err\n\t\t\t}\n\t\t\tdefer inFile.Close()\n\n\t\t\toutFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())\n\t\t\tif err != nil {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/zip.go#L5-L41","documentation":"Unzip rejects archive entries whose names contain \"..\" to prevent Zip Slip path traversal, returning \"%s 文件名不合法\" with the offending entry name. Without this check, a crafted zip could write files outside destDir. It is a security guard executed for every entry before extraction.","triggerScenarios":"Calling Unzip(zipPath, destDir) on an archive containing any entry whose f.Name includes \"..\" (e.g. \"../../etc/passwd\" or \"a/../b\"), produced intentionally or by archives created with absolute/relative parent paths.","commonSituations":"Processing user-uploaded zips (a classic Zip Slip attack vector); archives generated on Windows with backslash/.. segments; legacy tooling that zips with parent-relative paths; accepting untrusted archive uploads without scanning.","solutions":["Reject or sanitize the offending archive: inspect entry names with `unzip -l` / archive tool and remove entries containing \"..\".","Re-create the archive with clean, destination-relative entry paths and re-upload.","If you control the source, generate zips with paths relative to the archive root only.","Scan untrusted uploads for path traversal entries before extraction."],"exampleFix":"// before\npaths, err := ziputil.Unzip(\"evil.zip\", dest) // contains ../../secret\n\n// after\nif zipContainsTraversal(\"evil.zip\") { // pre-check entry names for \"..\"\n    return errors.New(\"archive rejected: path traversal entry\")\n}\npaths, err := ziputil.Unzip(\"evil.zip\", dest)","handlingStrategy":"validation","validationCode":"func zipHasTraversal(zipPath string) (bool, error) {\n    r, err := zip.OpenReader(zipPath)\n    if err != nil { return false, err }\n    defer r.Close()\n    for _, f := range r.File {\n        if strings.Contains(f.Name, \"..\") {\n            return true, nil\n        }\n    }\n    return false, nil\n}","typeGuard":null,"tryCatchPattern":"paths, err := ziputil.Unzip(zipPath, destDir)\nif err != nil {\n    if strings.Contains(err.Error(), \"文件名不合法\") {\n        return fmt.Errorf(\"archive rejected: unsafe entry path (possible zip slip): %w\", err)\n    }\n    return err\n}","preventionTips":["Always reject entries containing \"..\" before extraction","Scan user-uploaded archives for traversal entries before unzipping","Extract into a sandboxed temp directory with quota limits","Use filepath.Rel to verify resolved paths stay inside destDir"],"tags":["zip","security","path-traversal","upload"],"backgroundTag":"zip-slip-path-traversal","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}