{"record":{"id":"5ee66cfd3638d2b3","repo":"crowdsecurity/crowdsec","slug":"plugin-at-s-is-not-owned-by-user-s","errorCode":null,"errorMessage":"plugin at %s is not owned by user '%s'","messagePattern":"plugin at (.+?) is not owned by user '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csplugin/utils.go","lineNumber":115,"sourceCode":"\tvar err error\n\n\t// check if it exists\n\tif details, err = os.Stat(path); err != nil {\n\t\treturn fmt.Errorf(\"plugin at %s does not exist: %w\", path, err)\n\t}\n\n\t// check if it is owned by current user\n\tcurrentUser, err := user.Current()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while getting current user: %w\", err)\n\t}\n\tcurrentUID, err := getUID(currentUser.Username)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while looking up the current uid: %w\", err)\n\t}\n\tstat := details.Sys().(*syscall.Stat_t)\n\tif stat.Uid != currentUID {\n\t\treturn fmt.Errorf(\"plugin at %s is not owned by user '%s'\", path, currentUser.Username)\n\t}\n\n\tmode := details.Mode()\n\tperm := uint32(mode)\n\tif (perm & 0o0002) != 0 {\n\t\treturn fmt.Errorf(\"plugin at %s is world writable, world writable plugins are invalid\", path)\n\t}\n\tif (perm & 0o0020) != 0 {\n\t\treturn fmt.Errorf(\"plugin at %s is group writable, group writable plugins are invalid\", path)\n\t}\n\tif (mode & os.ModeSetgid) != 0 {\n\t\treturn fmt.Errorf(\"plugin at %s has setgid permission, which is not allowed\", path)\n\t}\n\treturn nil\n}\n","sourceCodeStart":97,"sourceCodeEnd":131,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csplugin/utils.go#L97-L131","documentation":"Security check in pluginIsValid: the plugin binary must be owned by the user running crowdsec. If the file's uid (from syscall.Stat_t) differs from the current user's uid, the plugin is rejected with this error.","triggerScenarios":"pluginIsValid stats the plugin binary, reads stat.Uid, and it does not equal the current process's uid — the binary was installed by root while crowdsec runs as an unprivileged user, or vice versa.","commonSituations":"Plugin installed with sudo (root-owned) but crowdsec daemon runs as user 'crowdsec'; plugin binary copied by hand as another user; ownership changed by a package update.","solutions":["chown the plugin binary to the user running crowdsec: chown crowdsec:crowdsec <plugin path>","Or install the plugin via the documented path/manner so it ends up owned by the service user","Check with ls -ln <path> that owner uid matches the crowdsec process uid (ps -o uid= -p $(pidof crowdsec))"],"exampleFix":"// before\nsudo cp notification-slack /usr/lib/crowdsec/plugins/\n// after\nsudo install -o crowdsec -g crowdsec notification-slack /usr/lib/crowdsec/plugins/","handlingStrategy":"validation","validationCode":"info, err := os.Stat(pluginPath)\nif err != nil { return err }\nif stat, ok := info.Sys().(*syscall.Stat_t); ok && int(stat.Uid) != os.Getuid() {\n    return fmt.Errorf(\"plugin %s not owned by current user\", pluginPath)\n}","typeGuard":null,"tryCatchPattern":"if err := pluginIsValid(path); err != nil {\n    if strings.Contains(err.Error(), \"is not owned by user\") {\n        log.Fatalf(\"chown the plugin to the crowdsec user: %v\", err)\n    }\n    return err\n}","preventionTips":["Install plugins with install -o <crowdsec-user> so ownership matches the service","Re-check ownership after package upgrades or manual copies","Run crowdsec and install plugins as the same user"],"tags":["go","plugin","ownership","security"],"backgroundTag":"permission-denied","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}