{"record":{"id":"8098c2afdadca44b","repo":"flipped-aurora/gin-vue-admin","slug":"invalid-plugin-name","errorCode":null,"errorMessage":"invalid plugin name","messagePattern":"invalid plugin name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/plugin_security.go","lineNumber":16,"sourceCode":"package utils\n\nimport (\n\t\"errors\"\n\t\"go/token\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar pluginNamePattern = regexp.MustCompile(`^[a-z][a-z0-9_]*$`)\n\n// ValidatePluginName restricts plugin names to lowercase ASCII Go identifiers.\nfunc ValidatePluginName(name string) error {\n\tif !pluginNamePattern.MatchString(name) || token.IsKeyword(name) {\n\t\treturn errors.New(\"invalid plugin name\")\n\t}\n\treturn nil\n}\n\n// JoinWithinRoot joins path elements while ensuring the result stays below root.\nfunc JoinWithinRoot(root string, elems ...string) (string, error) {\n\tif strings.TrimSpace(root) == \"\" {\n\t\treturn \"\", errors.New(\"path root is empty\")\n\t}\n\trootAbs, err := filepath.Abs(root)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"failed to resolve path root\")\n\t}\n\tfor _, elem := range elems {\n\t\tif filepath.IsAbs(elem) || filepath.VolumeName(elem) != \"\" || strings.HasPrefix(elem, \"/\") || strings.HasPrefix(elem, `\\`) {\n\t\t\treturn \"\", errors.New(\"path escapes root\")\n\t\t}\n\t}","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/plugin_security.go#L1-L34","documentation":"ValidatePluginName enforces that plugin names are lowercase ASCII Go identifiers (regex ^[a-z][a-z0-9_]*$) and not Go keywords. Names failing either check return 'invalid plugin name'; this guards against path traversal and code-injection when a name is used in paths or generated Go code.","triggerScenarios":"Passing names with uppercase letters, leading digits, hyphens, slashes/dots ('../evil', 'my-plugin', '1foo', 'Foo', 'type'), or a Go keyword like 'func'/'range' to ValidatePluginName (e.g. during plugin creation/generation tooling).","commonSituations":"Users typing plugin names in kebab-case ('my-plugin') per web convention; clipboard input carrying spaces or path separators; attempts to inject traversal sequences — intentionally rejected by this security check.","solutions":["Rename the plugin to match ^[a-z][a-z0-9_]*$: lowercase letters/digits/underscores, starting with a letter (e.g. 'myplugin' or 'my_plugin').","Avoid Go keywords as names ('type', 'range', 'func', etc.).","Sanitize/trim user input before validating (strip spaces, convert to lowercase) in the calling tool."],"exampleFix":"// before\nerr := utils.ValidatePluginName(\"my-plugin\") // invalid plugin name\n// after\nerr := utils.ValidatePluginName(\"my_plugin\") // nil","handlingStrategy":"validation","validationCode":"var pluginNamePattern = regexp.MustCompile(`^[a-z][a-z0-9_]*$`)\nfunc isValidPluginName(s string) bool {\n    return pluginNamePattern.MatchString(s) && !token.IsKeyword(s)\n}\nif !isValidPluginName(name) {\n    return fmt.Errorf(\"plugin name must match ^[a-z][a-z0-9_]*$ and not be a Go keyword\")\n}","typeGuard":null,"tryCatchPattern":"if err := utils.ValidatePluginName(name); err != nil {\n    return nil, fmt.Errorf(\"%q is not a valid plugin name: use lowercase letters, digits and underscores, starting with a letter\", name)\n}","preventionTips":["Normalize user input (lowercase, replace '-' with '_', trim) before validation","Document the naming rule wherever plugin names are entered","Never bypass ValidatePluginName to accept hyphenated or path-like names — it is a security control"],"tags":["security","validation","go","plugin"],"backgroundTag":"invalid-identifier-name","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}