Agent Wranglers

DSK-28Required

Check who is calling before a privileged helper acts

A helper or service that runs as root or SYSTEM accepts connections only from your own signed app, or from the signed-in users on Windows. It performs only actions from a fixed list, with checked arguments.

How to do it

Apps install helpers to update themselves or change system settings, and the helper has more rights than the user. If any local program can talk to it, malware gets those rights just by asking. On macOS 13 and later, NSXPCConnection.setCodeSigningRequirement refuses a peer that does not match your bundle ID and team ID. On Windows, a named pipe made without a security descriptor gives read access to Everyone and the anonymous account. Give the pipe a descriptor that allows only System and interactive users. Each request names one action from the list, never a path or a command to run as root. Never pass input to a shell explains why. Mac App Store apps may not ask for root at all, under App Review Guideline 2.4.5(v).

Examples

Plain text example

let callerRequirement = "anchor apple generic and identifier \"com.example.ledgerly\" and certificate leaf[subject.OU] = \"ABCDE12345\""

func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool {
    connection.setCodeSigningRequirement(callerRequirement)
    connection.exportedInterface = NSXPCInterface(with: HelperProtocol.self)
    connection.exportedObject = Helper()
    connection.resume()
    return true
}

Plain text example 2

var security = new PipeSecurity();
security.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.FullControl, AccessControlType.Allow));
security.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.InteractiveSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow));

using var pipe = NamedPipeServerStreamAcl.Create("ledgerly-helper", PipeDirection.InOut, 1,
    PipeTransmissionMode.Message, PipeOptions.Asynchronous, 0, 0, security);

How to check

A test signs a small program with another identity and connects it to the helper, which refuses it. A process from a network logon opens the Windows pipe and is refused. A request with an unknown action, or with a path outside the app's own folders, is refused.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/desktop-apps/installs-and-local-privileges/privileged-helper-callers">Agent Wranglers desktop apps and extensions playbook</a>. In code you write, add a comment next to it with the same link.