xtekky/gpt4free · critical
unsafe path in archive: %s
Error message
unsafe path in archive: %s
What it means
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).
Source
Thrown at g4f-go/process.go:86
}
}
if top == "" || top == "." {
return fmt.Errorf("archive has no top-level directory")
}
for _, f := range zr.File {
rel := f.Name
if top != "" {
rel = strings.TrimPrefix(f.Name, top+"/")
rel = strings.TrimPrefix(rel, top)
}
rel = strings.TrimPrefix(rel, "/")
name := filepath.Clean(rel)
if name == "." || name == "" {
continue // skip the top dir itself
}
if name == ".." || strings.HasPrefix(name, ".."+string(os.PathSeparator)) {
return fmt.Errorf("unsafe path in archive: %s", f.Name)
}
target := filepath.Join(dest, name)
if !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) && target != filepath.Clean(dest) {
return fmt.Errorf("unsafe path in archive: %s", f.Name)
}
if f.FileInfo().IsDir() {
if err := os.MkdirAll(target, 0o755); err != nil {
return err
}
continue
}
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
return err
}
rc, err := f.Open()
if err != nil {
return err
}View on GitHub (pinned to 973504e177)
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
Example fix
# before # unsafe path in archive: pyroot/../../evil.dll # after unzip -l runtime.zip | grep '\.\.' # confirm offending entries rm runtime.zip curl -L -o runtime.zip "<official-pinned-url>"
Defensive patterns
Strategy: validation
Validate before calling
// scan zip entries for traversal names before extracting
func zipIsSafe(path string) (bool, error) {
r, err := zip.OpenReader(path)
if err != nil { return false, err }
defer r.Close()
for _, f := range r.File {
name := filepath.Clean(f.Name)
if name == ".." || strings.HasPrefix(name, "..") {
return false, nil
}
}
return true, nil
} Try / catch
if err := extractZip(dest, r, size); err != nil && strings.Contains(err.Error(), "unsafe path in archive") {
// quarantine archive + re-verify provenance; do not retry as-is
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Runtime zips fetched from unofficial mirrors; tampered downloads (the guard doing its job); archives built with nonstandard tools emitting '..' components.
Related errors
- unsafe path in archive: %s
- archive has no top-level directory
- Failed to get conversation ID from /new: {new_data}
- sha256 mismatch: got %s, want %s
- extract runtime: %w
AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14).
Data as JSON: /api/errors/7d1bb98a3403a70b.
Report an issue: GitHub.