{"record":{"id":"7d1bb98a3403a70b","repo":"xtekky/gpt4free","slug":"unsafe-path-in-archive-s-7d1bb9","errorCode":null,"errorMessage":"unsafe path in archive: %s","messagePattern":"unsafe path in archive: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"g4f-go/process.go","lineNumber":86,"sourceCode":"\t\t}\n\t}\n\tif top == \"\" || top == \".\" {\n\t\treturn fmt.Errorf(\"archive has no top-level directory\")\n\t}\n\n\tfor _, f := range zr.File {\n\t\trel := f.Name\n\t\tif top != \"\" {\n\t\t\trel = strings.TrimPrefix(f.Name, top+\"/\")\n\t\t\trel = strings.TrimPrefix(rel, top)\n\t\t}\n\t\trel = strings.TrimPrefix(rel, \"/\")\n\t\tname := filepath.Clean(rel)\n\t\tif name == \".\" || name == \"\" {\n\t\t\tcontinue // skip the top dir itself\n\t\t}\n\t\tif name == \"..\" || strings.HasPrefix(name, \"..\"+string(os.PathSeparator)) {\n\t\t\treturn fmt.Errorf(\"unsafe path in archive: %s\", f.Name)\n\t\t}\n\t\ttarget := filepath.Join(dest, name)\n\t\tif !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) && target != filepath.Clean(dest) {\n\t\t\treturn fmt.Errorf(\"unsafe path in archive: %s\", f.Name)\n\t\t}\n\t\tif f.FileInfo().IsDir() {\n\t\t\tif err := os.MkdirAll(target, 0o755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\t\trc, err := f.Open()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f-go/process.go#L68-L104","documentation":"First zip-slip guard in g4f-go/process.go: after stripping the detected top-level directory and cleaning the name, an entry that is '..' or starts with '../' aborts with 'unsafe path in archive'. Same traversal protection as the tar path, applied to the runtime's zip flavor (typically the Windows python embeddable zip).","triggerScenarios":"A zip containing entries that reduce to parent directories after top-dir stripping, e.g. 'pyroot/../../evil.dll'. Occurs with crafted/malicious archives or broken repacking tools.","commonSituations":"Runtime zips fetched from unofficial mirrors; tampered downloads (the guard doing its job); archives built with nonstandard tools emitting '..' components.","solutions":["Stop and discard the archive; list offending entries: unzip -l archive.zip and inspect for '..' paths","Re-download from the official URL pinned in runtime.json","Ensure the sha256 pin in the manifest is current so tampered zips fail verification earlier","Never re-zip archives with path-junking tools that can produce traversal components"],"exampleFix":"# before\n# unsafe path in archive: pyroot/../../evil.dll\n\n# after\nunzip -l runtime.zip | grep '\\.\\.'    # confirm offending entries\nrm runtime.zip\ncurl -L -o runtime.zip \"<official-pinned-url>\"","handlingStrategy":"validation","validationCode":"// scan zip entries for traversal names before extracting\nfunc zipIsSafe(path string) (bool, error) {\n    r, err := zip.OpenReader(path)\n    if err != nil { return false, err }\n    defer r.Close()\n    for _, f := range r.File {\n        name := filepath.Clean(f.Name)\n        if name == \"..\" || strings.HasPrefix(name, \"..\") {\n            return false, nil\n        }\n    }\n    return true, nil\n}","typeGuard":null,"tryCatchPattern":"if err := extractZip(dest, r, size); err != nil && strings.Contains(err.Error(), \"unsafe path in archive\") {\n    // quarantine archive + re-verify provenance; do not retry as-is\n}","preventionTips":["Download runtime zips only from the sha256-pinned official URL","Scan archives for '..' entries in your CI before release","Escalate traversal hits to a security review, not a retry"],"tags":["go","security","path-traversal","zip-slip","zip","extraction"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}