crowdsecurity/crowdsec · error
plugin at is not owned by SYSTEM, Administrators or by…
Error message
plugin at %s is not owned by SYSTEM, Administrators or by current user, but by %s
What it means
This is a deliberate security-policy rejection, not a system failure. CheckPerms verifies the plugin binary's owner is SYSTEM, BUILTIN\Administrators, or the user running crowdsec; if a regular/unprivileged account owns the file, any such account could silently replace the binary with malicious code that crowdsec would execute. The error names the offending owner SID.
Solutions
- Take ownership as an administrator: `icacls <plugin> /setowner Administrators` or takeown.exe
- Reinstall the plugins using an elevated installer/process so files are owned by Administrators
- Move plugins to the standard install directory and set ownership there
- Verify with `icacls <plugin>` that the owner is SYSTEM, Administrators, or crowdsec's service account
Example fix
// before # plugin copied by user 'dev' → owner dev C:\ProgramData\crowdsec\plugins> icacls notify-email.exe ... Owner: CORP\dev // after # run elevated icacls "C:\ProgramData\crowdsec\plugins\notify-email.exe" /setowner Administrators
Defensive patterns
Strategy: validation
Validate before calling
func pluginOwnerIsTrusted(path string) error {
sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
if err != nil {
return err
}
owner, _, err := sd.Owner()
if err != nil {
return err
}
s, err := owner.String()
if err != nil {
return err
}
switch s {
case "S-1-5-18", "S-1-5-32-544": // SYSTEM, Administrators
return nil
}
return fmt.Errorf("untrusted owner %s on %s", s, path)
} Prevention
- Install plugins with an elevated installer so ownership is Administrators
- Never leave plugin files owned by interactive users
- Check `icacls <plugin>` after any manual copy or extraction
- Deploy plugins via scripts that run as SYSTEM
When it happens
Trigger: Calling CheckPerms (via pluginIsValid, during plugin discovery) on a plugin binary whose NTFS owner is a normal user account — e.g. a plugin installed by hand by a non-admin user, extracted from an archive preserving an odd owner, or copied onto the machine by a non-elevated process.
Common situations: Plugins unzipped by a logged-in user instead of an elevated installer; plugins deployed by CI/CD or scripts running as a service account different from crowdsec's; files restored from backups with rewritten ownership; plugins in a user-profile folder rather than a system plugin directory.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- only SYSTEM, Administrators or the user currently running…
- owner is invalid
- security descriptor is invalid
- no DACL found on plugin, meaning fully permissive access on…
- plugin at has setgid permission, which is not allowed
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/ec98b24abe787edb.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/csplugin/utils_windows.go:98
}
sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION)
if err != nil {
return fmt.Errorf("while getting owner security info: %w", err)
}
if !sd.IsValid() {
return errors.New("security descriptor is invalid")
}
owner, _, err := sd.Owner()
if err != nil {
return fmt.Errorf("while getting owner: %w", err)
}
if !owner.IsValid() {
return errors.New("owner is invalid")
}
if !owner.Equals(systemSid) && !owner.Equals(currentUserSid) && !owner.Equals(adminSid) {
return fmt.Errorf("plugin at %s is not owned by SYSTEM, Administrators or by current user, but by %s", path, owner.String())
}
dacl, _, err := sd.DACL()
if err != nil {
return fmt.Errorf("while getting DACL: %w", err)
}
if dacl == nil {
return fmt.Errorf("no DACL found on plugin, meaning fully permissive access on plugin %s", path)
}
rs := reflect.ValueOf(dacl).Elem()
/*
For reference, the structure of the ACL type is:
type ACL struct {
aclRevision byte
sbz1 byteView on GitHub (pinned to 909b515798)