coreybutler/nvm-windows · critical
illegal file path: %s
Error message
illegal file path: %s
What it means
During nvm-windows' unzip of a downloaded node archive, each entry's target path is checked against filepath.Clean(dest)+separator. This 'illegal file path' error is the ZipSlip guard firing: the archive contains an entry whose Name resolves OUTSIDE the intended destination (via ../ segments or absolute paths), and nvm refuses to extract it as a security measure.
Source
Thrown at src/web/web.go:473
os.MkdirAll(dest, 0755)
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
}
}()
path := filepath.Join(dest, f.Name)
// Check for ZipSlip (Directory traversal)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
os.MkdirAll(filepath.Dir(path), f.Mode())
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
_, err = io.Copy(f, rc)
if err != nil {View on GitHub (pinned to 5b18223ca1)
Solutions
- Immediately switch back to the official mirror (unset NVM_NODE_MIRROR / point to https://nodejs.org/dist) — a ZipSlip hit strongly suggests a tampered or broken mirror.
- Delete the cached downloaded zip so nvm re-downloads from the good mirror.
- Verify the archive manually: download it, list entries (e.g. via a zip tool), and confirm no entry escapes the root.
- Check the mirror URL for typos in settings.txt (node_mirror / npm_mirror).
Example fix
// before
path := filepath.Join(dest, f.Name)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}
// after: same guard, but name the attack class to guide users to the mirror fix
path := filepath.Join(dest, f.Name)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("zipslip detected: archive entry %q escapes destination %s — the download is likely corrupted or from a tampered mirror; re-download from an official mirror", f.Name, dest)
} Defensive patterns
Strategy: validation
Validate before calling
// Validate every zip entry stays under dest before extracting
func zipSafe(r *zip.ReadCloser, dest string) error {
target := filepath.Clean(dest) + string(os.PathSeparator)
for _, f := range r.File {
p := filepath.Clean(filepath.Join(dest, f.Name))
if !strings.HasPrefix(p, target) || filepath.IsAbs(f.Name) {
return fmt.Errorf("unsafe entry %q", f.Name)
}
}
return nil
} Try / catch
if err := unzip(src, dest); err != nil {
if strings.Contains(err.Error(), "illegal file path") {
os.Remove(src) // discard suspect archive
return errors.New("download failed integrity check — switched to official mirror required")
}
} Prevention
- Only use official or well-known mirrors for node/npm archives.
- Delete cached archives when a mirror misbehaves so fresh copies download.
- Treat any ZipSlip hit as possible tampering — investigate the mirror.
When it happens
Trigger: Downloading a corrupted or tampered node archive (mirror serving a malicious/rewritten zip), or an archive with entry names like '../../windows/system32/x' or 'C:\Windows\...'. The HasPrefix check fails and extraction aborts.
Common situations: Third-party/unofficial mirrors serving repackaged archives; corrupted downloads where entry names are garbage; extremely rare with official nodejs.org — almost always a bad mirror URL.
Related errors
- Failed to extract npm. Could not find %s
- Failed to extract npm: %v
- Could not retrieve %v: %v
- Error retrieving "%s": HTTP Status %v
AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15).
Data as JSON: /api/errors/f441480ee6feb0d8.
Report an issue: GitHub.