astrid-runtime/astrid · error

named-pipe DACL grants an unexpected or duplicate principal

Error message

named-pipe DACL grants an unexpected or duplicate principal

What it means

After confirming each ACE is a full-control allow entry, the library checks the ACE's SID: each must be the current user's SID or the Local System SID, each appearing at most once. This error means the DACL grants access to some other principal (a group, another user, Everyone) or duplicates a SID — the pipe's ACL was not produced by this library and could expose IPC traffic to third parties, so it fails with PermissionDenied.

Source

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

    for index in 0..ace_count {
        let ValidatedAce::Allow { flags, mask, sid } = dacl.ace(index)? else {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL contains a non-canonical access entry",
            ));
        };
        if flags != 0 || !is_canonical_pipe_full_control(mask) {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL contains a non-canonical access entry",
            ));
        }
        if unsafe { EqualSid(sid.as_ptr(), current.as_psid()) } != 0 && !saw_current {
            saw_current = true;
        } else if unsafe { EqualSid(sid.as_ptr(), system.as_psid()) } != 0 && !saw_system {
            saw_system = true;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "named-pipe DACL grants an unexpected or duplicate principal",
            ));
        }
    }

    if !saw_current || !saw_system {
        return Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "named-pipe DACL omits the current user or Local System",
        ));
    }
    Ok(())
}

fn is_canonical_pipe_full_control(mask: u32) -> bool {
    // The I/O manager maps generic access bits to the file-object-specific
    // mask when attaching a descriptor to a named pipe. Accept the exact SDDL

View on GitHub (pinned to affd8760f4)

Solutions

  1. Delete and recreate the pipe via the library so only current user + SYSTEM ACEs exist.
  2. Inspect with `Get-Acl \\.\pipe\<name>` and remove ACEs for other principals (Everyone, Users, service accounts).
  3. Disable ACL inheritance on the pipe's security descriptor (SE_DACL_PROTECTED) in whatever creates it.
  4. Run creator and consumer under the same user so no additional grant is needed.

Example fix

// before: broad access for debugging
"D:P(A;;GA;;;WD)(A;;GA;;;SY)" // Everyone
// after: only current user and Local System
"D:P(A;;GA;;;CURRENT_USER)(A;;GA;;;SY)"
Defensive patterns

Strategy: validation

Validate before calling

// PowerShell preflight: allowed principals must be exactly the current user and SYSTEM
// (Get-Acl \\.\pipe\myapp).Access | Select IdentityReference

Try / catch

match connect() {
    Err(e) if e.to_string().contains("unexpected or duplicate principal") => {
        eprintln!("pipe DACL grants extra principals; recreate pipe with only current user + SYSTEM");
    }
    r => r?,
}

Prevention

When it happens

Trigger: connect()/accept() where a DACL ACE's SID matches neither the current user SID nor WinLocalSystemSid, or matches one already seen (duplicate entry) during the loop in validate_pipe_security.

Common situations: Someone granted access to a group (Users, Authenticated Users) to ease debugging; ACL inheritance pulled in extra principals; multiple overlapping ACEs for the same SID after ACL edits; the pipe is owned by different software with a shared-access ACL.

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/45d81dc4f7bbbb22. Report an issue: GitHub.