router-for-me/CLIProxyAPI · error

zip entry has empty name

Error message

zip entry has empty name

What it means

Returned by cleanZipName (install.go:375-378) when a zip entry's name is empty or only whitespace. Entry names are sanitized before any matching happens, and an unnamed entry is treated as malformed input — it cannot be safely mapped to a filesystem path, so the whole install is rejected.

Source

Thrown at internal/pluginstore/install.go:377

	}()
	data, errRead := io.ReadAll(handle)
	if errRead != nil {
		return nil, 0, fmt.Errorf("read %s: %w", targetName, errRead)
	}
	mode := target.FileInfo().Mode().Perm()
	if mode == 0 {
		mode = 0o755
	}
	return data, mode, nil
}

func versionedPluginFileName(id string, version string, goos string) string {
	return strings.TrimSpace(id) + "-v" + normalizeVersion(version) + pluginExtension(goos)
}

func cleanZipName(name string) (string, error) {
	if strings.TrimSpace(name) == "" {
		return "", fmt.Errorf("zip entry has empty name")
	}
	if strings.Contains(name, `\`) {
		return "", fmt.Errorf("zip entry %s uses backslash path separators", name)
	}
	if path.IsAbs(name) {
		return "", fmt.Errorf("zip entry %s is absolute", name)
	}
	cleaned := path.Clean(name)
	if cleaned == "." || cleaned == ".." || strings.HasPrefix(cleaned, "../") {
		return "", fmt.Errorf("zip entry %s escapes archive root", name)
	}
	return cleaned, nil
}

func regularZipFile(file *zip.File) bool {
	mode := file.FileInfo().Mode()
	return mode.IsRegular() || mode.Type() == 0
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Rebuild the zip from a known-good source and confirm every entry has a name: unzip -l artifact.zip
  2. If producing archives programmatically, assert entry names are non-empty before writing them
  3. Reject or quarantine the artifact at whatever boundary accepted it — an empty entry name signals a malformed or hostile archive
Defensive patterns

Strategy: validation

Validate before calling

func entriesNamed(archiveData []byte) error {
    r, err := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))
    if err != nil { return err }
    for _, f := range r.File {
        if strings.TrimSpace(f.Name) == "" {
            return fmt.Errorf("rejecting archive: entry %d has empty name", f.Name)
        }
    }
    return nil
}

Try / catch

if err := entriesNamed(data); err != nil {
    // quarantine artifact before it reaches InstallArchive
} else if _, err := store.InstallArchive(data, plugin, opts); err != nil { /* handle */ }

Prevention

When it happens

Trigger: InstallArchive on a zip containing an entry whose Name field is "" or " ". This happens with hand-crafted zips, some zip libraries that allow zero-length names, or deliberately malformed archives (the check is also a hardening measure against path manipulation).

Common situations: A test fixture or script-generated zip built with a library that permits empty entry names; fuzzed or hostile archives fed to an install endpoint.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/1e186221be4e71b3. Report an issue: GitHub.