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
- Rebuild the zip from a known-good source and confirm every entry has a name: unzip -l artifact.zip
- If producing archives programmatically, assert entry names are non-empty before writing them
- 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
- Only accept archives from trusted release pipelines, never arbitrary uploads
- When building zips programmatically, assert non-empty entry names at write time
- Fuzz-test any HTTP endpoint that accepts archives for install
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
- zip entry %s uses backslash path separators
- zip entry %s is absolute
- zip entry %s escapes archive root
- invalid name
- invalid auth file name
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/1e186221be4e71b3.
Report an issue: GitHub.