{"record":{"id":"ad867ed28f2eefe8","repo":"golang/go","slug":"invalid-file-name-v","errorCode":null,"errorMessage":"invalid file name: %v","messagePattern":"invalid file name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/archive/zip/reader.go","lineNumber":981,"sourceCode":"\tif count > 0 && n > count {\n\t\tn = count\n\t}\n\tif n == 0 {\n\t\tif count <= 0 {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, io.EOF\n\t}\n\tlist := make([]fs.DirEntry, n)\n\tfor i := range list {\n\t\ts, err := d.files[d.offset+i].stat()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t} else if s.Name() == \".\" || !fs.ValidPath(s.Name()) {\n\t\t\treturn nil, &fs.PathError{\n\t\t\t\tOp:   \"readdir\",\n\t\t\t\tPath: d.e.name,\n\t\t\t\tErr:  fmt.Errorf(\"invalid file name: %v\", d.files[d.offset+i].name),\n\t\t\t}\n\t\t}\n\t\tlist[i] = s\n\t}\n\td.offset += n\n\treturn list, nil\n}\n","sourceCodeStart":963,"sourceCodeEnd":989,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/archive/zip/reader.go#L963-L989","documentation":"Returned by (*zip.openDir).ReadDir (reader.go:981) as an fs.PathError when a directory entry inside the zip has a name that is '.', '..', empty, contains a slash (i.e., is not a single path element), or otherwise fails fs.ValidPath. The zip reader exposes archives as an fs.FS and must guarantee each entry name is a valid path element.","triggerScenarios":"Calling ReadDir (via fs.ReadDir on a zip-opened directory, or fs.WalkDir over a zip fs.FS) on a zip whose entries contain backslashes (Windows paths), absolute paths, leading '/', '.', '..', or empty names. Such entries are valid in raw zip but invalid as fs.FS nodes.","commonSituations":"Zips produced by Windows archivers using '\\' separators; archives with absolute entry names like '/etc/passwd'; entries named '.' or containing '..' segments; zips crafted with malicious path components (zip-slip style); mixing directory and file separators.","solutions":["Re-create the zip with unix-style relative single-element names per entry (no leading '/', no '\\', no '.'/'..' segments).","If you must read a non-conforming zip, use zip.OpenReader and iterate FileHeader slices directly instead of the fs.FS interface.","Sanitize entry names before re-archiving: filepath.ToSlash + filepath.Clean, refuse absolute paths.","Validate with fs.ValidPath before adding entries when producing zips."],"exampleFix":"// before\nzfs, _ := zip.OpenReader(\"win.zip\")\nfs.WalkDir(zfs, \".\", ...) // -> invalid file name on '\\' entries\n\n// after\nzr, _ := zip.OpenReader(\"win.zip\")\nfor _, f := range zr.File {\n    name := path.Clean(filepath.ToSlash(f.Name)) // normalize manually\n    ... // process via f.Open() directly\n}","handlingStrategy":"validation","validationCode":"// Validate entry names before exposing a zip as fs.FS.\nfunc zipEntryNamesValid(zr *zip.ReadCloser) error {\n    for _, f := range zr.File {\n        name := filepath.ToSlash(f.Name)\n        if !fs.ValidPath(name) && name != \"/\" {\n            return fmt.Errorf(\"invalid entry name %q\", f.Name)\n        }\n    }\n    return nil\n}","typeGuard":"func validZipEntryName(name string) bool {\n    return fs.ValidPath(filepath.ToSlash(name))\n}","tryCatchPattern":null,"preventionTips":["Produce zips with unix-style relative single-element names per entry.","For non-conforming zips, iterate FileHeader slices directly instead of using fs.FS.","Sanitize with filepath.ToSlash + path.Clean and reject absolute paths before re-archiving."],"tags":["archive","zip","fs-fs","path-validation","windows"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}