{"record":{"id":"81bd73e8de37b354","repo":"router-for-me/CLIProxyAPI","slug":"zip-entry-s-is-not-a-regular-file","errorCode":null,"errorMessage":"zip entry %s is not a regular file","messagePattern":"zip entry (.+?) is not a regular file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":331,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"invalid plugin version %q\", version)\n\t}\n\treturn filepath.Join(options.PluginsDir, options.GOOS, options.GOARCH, versionedPluginFileName(id, version, options.GOOS)), nil\n}\n\nfunc readTargetLibrary(reader *zip.Reader, id string, version string, goos string) ([]byte, os.FileMode, error) {\n\ttargetName := strings.TrimSpace(id) + pluginExtension(goos)\n\tversionedTargetName := versionedPluginFileName(id, version, goos)\n\tvar target *zip.File\n\tfor _, file := range reader.File {\n\t\tcleanedName, errClean := cleanZipName(file.Name)\n\t\tif errClean != nil {\n\t\t\treturn nil, 0, errClean\n\t\t}\n\t\tif file.FileInfo().IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tif !regularZipFile(file) {\n\t\t\treturn nil, 0, fmt.Errorf(\"zip entry %s is not a regular file\", file.Name)\n\t\t}\n\t\tif !hasDynamicLibraryExtension(cleanedName) {\n\t\t\tcontinue\n\t\t}\n\t\tif cleanedName != targetName && cleanedName != versionedTargetName {\n\t\t\tif path.Base(cleanedName) == targetName || path.Base(cleanedName) == versionedTargetName {\n\t\t\t\treturn nil, 0, fmt.Errorf(\"target dynamic library must be at zip root\")\n\t\t\t}\n\t\t\treturn nil, 0, fmt.Errorf(\"dynamic library filename must be %s or %s\", targetName, versionedTargetName)\n\t\t}\n\t\tif target != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"zip contains multiple target dynamic libraries\")\n\t\t}\n\t\ttarget = file\n\t}\n\tif target == nil {\n\t\treturn nil, 0, fmt.Errorf(\"zip does not contain %s\", targetName)\n\t}","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L313-L349","documentation":"Thrown by readTargetLibrary while scanning the archive: a zip entry that is neither a directory nor a regular file (regularZipFile false — e.g. a symlink, device, or FIFO mode). The extractor refuses non-regular entries to prevent symlink-based attacks and unextractable special files; it scans every entry with a dynamic-library extension, so an unexpected mode on any matching entry aborts the install.","triggerScenarios":"An archive containing a symlink named like the plugin library (e.g. 'myplugin.so -> ../../system.so'), or entries created by archive tools that record unusual unix modes; triggered as soon as such an entry has a dynamic library extension.","commonSituations":"Repacking plugins with 'zip -y' (preserves symlinks) on Linux; malicious or tampered artifacts attempting path redirection; archives built by nonstandard tooling emitting odd external attributes.","solutions":["Rebuild the archive with real file contents instead of symlinks (zip without -y, or cp -L before zipping)","If consuming third-party artifacts, reject the artifact at the checksum/verification layer and report it upstream","Inspect with 'zipinfo -l' to find the non-regular entry"],"exampleFix":"# before\nln -s /opt/lib/real.so myplugin.so && zip -y plugin.zip myplugin.so # symlink stored\n\n# after\ncp /opt/lib/real.so myplugin.so && zip plugin.zip myplugin.so # regular file stored","handlingStrategy":"validation","validationCode":"func archiveHasOnlyRegularEntries(data []byte) error {\n    zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))\n    if err != nil {\n        return err\n    }\n    for _, f := range zr.File {\n        mode := f.FileInfo().Mode()\n        if mode.IsDir() {\n            continue\n        }\n        if !mode.IsRegular() {\n            return fmt.Errorf(\"entry %s has mode %v (not a regular file)\", f.Name, mode)\n        }\n    }\n    return nil\n}","typeGuard":"func isNonRegularZipEntry(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"is not a regular file\")\n}","tryCatchPattern":"if _, err := pluginstore.InstallArchive(data, plugin, options); err != nil {\n    if isNonRegularZipEntry(err) {\n        // reject artifact: rebuild archive without symlinks (zip without -y)\n    }\n}","preventionTips":["Never zip with symlink preservation (-y) for distributable artifacts","Add a packaging CI step asserting all entries are regular files","Treat non-regular entries in third-party artifacts as suspicious (possible tampering)"],"tags":["go","plugin-store","zip","security","symlink"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}