crowdsecurity/crowdsec · error
while getting ACE: %w
Error message
while getting ACE: %w
What it means
CheckPerms walks the plugin's ACL entries by calling the Win32 GetAce API via advapi32.dll (procGetAce.Call). If GetAce returns 0 (failure), this error wraps windows.GetLastError(), meaning the i-th ACE could not be retrieved from the DACL. Causes include an index beyond aceCount, a corrupt ACL, or reflection-derived aceCount mismatching the real ACL state (e.g. the ACL changed concurrently).
Source
Thrown at pkg/csplugin/utils_windows.go:129
/*
For reference, the structure of the ACL type is:
type ACL struct {
aclRevision byte
sbz1 byte
aclSize uint16
aceCount uint16
sbz2 uint16
}
As the field are not exported, we have to use reflection to access them, this should not be an issue as the structure won't (probably) change any time soon.
*/
aceCount := rs.Field(3).Uint()
for i := range aceCount {
ace := &AccessAllowedAce{}
ret, _, _ := procGetAce.Call(uintptr(unsafe.Pointer(dacl)), uintptr(i), uintptr(unsafe.Pointer(&ace)))
if ret == 0 {
return fmt.Errorf("while getting ACE: %w", windows.GetLastError())
}
log.Debugf("ACE %d: %+v\n", i, ace)
if ace.AceType == ACCESS_DENIED_ACE_TYPE {
continue
}
aceSid := (*windows.SID)(unsafe.Pointer(&ace.SidStart))
if aceSid.Equals(systemSid) || aceSid.Equals(adminSid) {
log.Debugf("Not checking permission for well-known SID %s", aceSid.String())
continue
}
if aceSid.Equals(currentUserSid) {
log.Debugf("Not checking permission for current user %s", currentUser.Username)
continue
}
View on GitHub (pinned to 909b515798)
Solutions
- Re-run crowdsec once ACL churn settles — a transient race often resolves on retry
- Reset and re-apply a stable ACL: `icacls <plugin> /reset` then `icacls <plugin> /grant ...`
- Exclude the crowdsec plugin directory from antivirus ACL-rewriting policies
- Read the wrapped GetLastError() code to confirm the specific Win32 failure
Example fix
// before
ret, _, _ := procGetAce.Call(uintptr(unsafe.Pointer(dacl)), uintptr(i), uintptr(unsafe.Pointer(&ace)))
if ret == 0 {
return fmt.Errorf("while getting ACE: %w", windows.GetLastError())
}
// after
ret, _, _ := procGetAce.Call(uintptr(unsafe.Pointer(dacl)), uintptr(i), uintptr(unsafe.Pointer(&ace)))
if ret == 0 {
return fmt.Errorf("while getting ACE %d of %d for %s: %w", i, aceCount, path, windows.GetLastError())
} Defensive patterns
Strategy: retry
Validate before calling
// ensure ACL size fields are consistent before enumeration
sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION)
if err != nil || !sd.IsValid() {
return errors.New("DACL not reliably readable")
} Try / catch
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
err := CheckPerms(pluginPath)
if err == nil {
break
}
if strings.Contains(err.Error(), "while getting ACE") {
lastErr = err
time.Sleep(500 * time.Millisecond) // ACL may be mid-modification
continue
}
return err
}
return lastErr Prevention
- Don't modify plugin-directory ACLs while crowdsec is running
- Exclude the plugin directory from ACL-rewriting security software
- Apply ACL changes in a single atomic operation (one icacls command)
When it happens
Trigger: Calling CheckPerms when procGetAce.Call fails for some index i: ACL was modified between reading aceCount and enumerating; ACL revision/size fields inconsistent with actual memory; malformed ACL on the file.
Common situations: Antivirus/EDR or group policy rewriting plugin-directory ACLs while crowdsec is enumerating them; corrupted ACLs from backup/restore tools; races when multiple processes adjust ACLs simultaneously.
Related errors
- while creating built-in Administrators well known sid: %w
- while getting owner security info: %w
- while getting owner: %w
- while getting DACL: %w
- no DACL found on plugin, meaning fully permissive access on
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/dd49780b87ac2af5.
Report an issue: GitHub.