xtekky/gpt4free · critical

unsafe path in archive

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).

Solutions

  1. Stop and discard the archive; list offending entries: unzip -l archive.zip and inspect for '..' paths
  2. Re-download from the official URL pinned in runtime.json
  3. Ensure the sha256 pin in the manifest is current so tampered zips fail verification earlier
  4. 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

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


AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14). Data as JSON: /api/errors/7d1bb98a3403a70b. Report an issue: GitHub.

Appendix: 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)