crowdsecurity/crowdsec · error
plugin at %s is not owned by user '%s'
Error message
plugin at %s is not owned by user '%s'
What it means
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.
Source
Thrown at pkg/csplugin/utils.go:115
var err error
// check if it exists
if details, err = os.Stat(path); err != nil {
return fmt.Errorf("plugin at %s does not exist: %w", path, err)
}
// check if it is owned by current user
currentUser, err := user.Current()
if err != nil {
return fmt.Errorf("while getting current user: %w", err)
}
currentUID, err := getUID(currentUser.Username)
if err != nil {
return fmt.Errorf("while looking up the current uid: %w", err)
}
stat := details.Sys().(*syscall.Stat_t)
if stat.Uid != currentUID {
return fmt.Errorf("plugin at %s is not owned by user '%s'", path, currentUser.Username)
}
mode := details.Mode()
perm := uint32(mode)
if (perm & 0o0002) != 0 {
return fmt.Errorf("plugin at %s is world writable, world writable plugins are invalid", path)
}
if (perm & 0o0020) != 0 {
return fmt.Errorf("plugin at %s is group writable, group writable plugins are invalid", path)
}
if (mode & os.ModeSetgid) != 0 {
return fmt.Errorf("plugin at %s has setgid permission, which is not allowed", path)
}
return nil
}
View on GitHub (pinned to 909b515798)
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))
Example fix
// before sudo cp notification-slack /usr/lib/crowdsec/plugins/ // after sudo install -o crowdsec -g crowdsec notification-slack /usr/lib/crowdsec/plugins/
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(pluginPath)
if err != nil { return err }
if stat, ok := info.Sys().(*syscall.Stat_t); ok && int(stat.Uid) != os.Getuid() {
return fmt.Errorf("plugin %s not owned by current user", pluginPath)
} Try / catch
if err := pluginIsValid(path); err != nil {
if strings.Contains(err.Error(), "is not owned by user") {
log.Fatalf("chown the plugin to the crowdsec user: %v", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- plugin at %s is world writable, world writable plugins are i
- plugin at %s is group writable, group writable plugins are i
- plugin at %s has setgid permission, which is not allowed
- token value for api.server.auto_register is too short (min 3
- out of bound gid
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/5ee66cfd3638d2b3.
Report an issue: GitHub.