astrid-runtime/astrid · error

named-pipe DACL control is not explicit and protected (contr

Error message

named-pipe DACL control is not explicit and protected (control=0x{control:04x})

What it means

validate_descriptor_control checks the security descriptor's control bits before any ACE inspection: the DACL must be explicitly PRESENT and PROTECTED, and must not be DEFAULTED or auto-inherited. This error (with the actual control bitmask in hex) means the pipe's DACL is inherited or auto-inherited rather than explicit, so its contents could change outside the library's control; connect/accept refuse the pipe.

Source

Thrown at crates/astrid-core/src/local_transport/windows/acl.rs:42

pub(super) unsafe fn validate_descriptor_control(
    descriptor: PSECURITY_DESCRIPTOR,
) -> io::Result<()> {
    let mut control = 0_u16;
    let mut revision = 0_u32;
    // SAFETY: the descriptor is the live allocation returned by
    // GetSecurityInfo and both outputs have the documented types.
    if unsafe { GetSecurityDescriptorControl(descriptor, &raw mut control, &raw mut revision) } == 0
    {
        return Err(super::last_error(
            "failed to inspect named-pipe security descriptor control",
        ));
    }
    let required = SE_DACL_PRESENT | SE_DACL_PROTECTED;
    let rejected = SE_DACL_DEFAULTED | SE_DACL_AUTO_INHERITED | SE_DACL_AUTO_INHERIT_REQ;
    if control & required == required && control & rejected == 0 {
        Ok(())
    } else {
        Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            format!(
                "named-pipe DACL control is not explicit and protected (control=0x{control:04x})"
            ),
        ))
    }
}

#[derive(Clone, Copy, Debug)]
pub(super) struct ValidatedSid<'acl> {
    pointer: PSID,
    _acl: PhantomData<&'acl ACL>,
}

impl ValidatedSid<'_> {
    pub(super) fn as_ptr(self) -> PSID {
        self.pointer
    }

View on GitHub (pinned to affd8760f4)

Solutions

  1. Recreate the pipe with this library, which builds a descriptor with SE_DACL_PRESENT|SE_DACL_PROTECTED.
  2. If constructing SDDL yourself, prefix the DACL with 'P' (protected): `D:P(A;;GA;;;...)`.
  3. Check for background ACL re-application (GPO, icacls scripts) on the pipe and exclude its path.
  4. Update the component creating the pipe — older versions may not set the protected flag.

Example fix

// before: unprotected SDDL (inherits)
"D:(A;;GA;;;CURRENT_USER)(A;;GA;;;SY)"
// after: protected DACL
"D:P(A;;GA;;;CURRENT_USER)(A;;GA;;;SY)"
Defensive patterns

Strategy: validation

Validate before calling

// Preflight: DACL must be protected from inheritance
// powershell: if (-not (Get-Acl \\.\pipe\myapp).AreAccessRulesProtected) { 'DACL is inherited/unprotected' }

Try / catch

match connect() {
    Err(e) if e.to_string().contains("not explicit and protected") => {
        eprintln!("pipe DACL inherited; recreate with protected SDDL 'D:P(...)' via this library");
    }
    r => r?,
}

Prevention

When it happens

Trigger: validate_pipe_security (via connect/accept) on a pipe whose descriptor control bits lack SE_DACL_PRESENT|SE_DACL_PROTECTED or contain SE_DACL_DEFAULTED / SE_DACL_AUTO_INHERITED / SE_DACL_AUTO_INHERIT_REQ.

Common situations: The pipe inherits its DACL from a parent directory/object because the creator passed a NULL security descriptor or an unprotected one; hardening/GPO tooling re-applied inherited ACLs; the pipe was created by another library version that did not set SE_DACL_PROTECTED.

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/a7883d07eeb5b493. Report an issue: GitHub.