{"record":{"id":"f441480ee6feb0d8","repo":"coreybutler/nvm-windows","slug":"illegal-file-path-s","errorCode":null,"errorMessage":"illegal file path: %s","messagePattern":"illegal file path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/web/web.go","lineNumber":473,"sourceCode":"\tos.MkdirAll(dest, 0755)\n\n\t// Closure to address file descriptors issue with all the deferred .Close() methods\n\textractAndWriteFile := func(f *zip.File) error {\n\t\trc, err := f.Open()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {\n\t\t\tif err := rc.Close(); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}()\n\n\t\tpath := filepath.Join(dest, f.Name)\n\n\t\t// Check for ZipSlip (Directory traversal)\n\t\tif !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {\n\t\t\treturn fmt.Errorf(\"illegal file path: %s\", path)\n\t\t}\n\n\t\tif f.FileInfo().IsDir() {\n\t\t\tos.MkdirAll(path, f.Mode())\n\t\t} else {\n\t\t\tos.MkdirAll(filepath.Dir(path), f.Mode())\n\t\t\tf, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\tif err := f.Close(); err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\t_, err = io.Copy(f, rc)\n\t\t\tif err != nil {","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/coreybutler/nvm-windows/blob/5b18223ca19ff50d707f35410dbc6bd440a9f74d/src/web/web.go#L455-L491","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\npath := filepath.Join(dest, f.Name)\nif !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {\n    return fmt.Errorf(\"illegal file path: %s\", path)\n}\n\n// after: same guard, but name the attack class to guide users to the mirror fix\npath := filepath.Join(dest, f.Name)\nif !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {\n    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)\n}","handlingStrategy":"validation","validationCode":"// Validate every zip entry stays under dest before extracting\nfunc zipSafe(r *zip.ReadCloser, dest string) error {\n    target := filepath.Clean(dest) + string(os.PathSeparator)\n    for _, f := range r.File {\n        p := filepath.Clean(filepath.Join(dest, f.Name))\n        if !strings.HasPrefix(p, target) || filepath.IsAbs(f.Name) {\n            return fmt.Errorf(\"unsafe entry %q\", f.Name)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := unzip(src, dest); err != nil {\n    if strings.Contains(err.Error(), \"illegal file path\") {\n        os.Remove(src) // discard suspect archive\n        return errors.New(\"download failed integrity check — switched to official mirror required\")\n    }\n}","preventionTips":["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."],"tags":["security","zipslip","archive","extraction","mirror","path-traversal"],"backgroundTag":null,"analyzedSha":"5b18223ca19ff50d707f35410dbc6bd440a9f74d","analyzedAt":"2026-08-15T10:06:51.428Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}