XPC Services: How macOS Processes Talk to Each Other Securely
The inter-process communication framework behind most of macOS's privilege separation, built on Mach IPC but designed to make secure, sandboxed communication the easy default rather than an afterthought.
A huge amount of what macOS does behind the scenes involves one process asking another, more privileged (or differently privileged) process to do something on its behalf — a sandboxed application asking for file access outside its container, a system service performing a privileged operation for an unprivileged client — and XPC is the framework Apple built specifically to make that kind of cross-process communication both convenient for developers and secure by construction.
The underlying primitive: Mach ports and messages
XPC is built directly on top of Mach IPC — specifically, Mach ports (kernel-managed communication endpoints) and Mach messages (the data sent through them). Mach’s IPC model was designed from the start around the idea of communication as a first-class, kernel-mediated primitive rather than something layered on top of shared memory or files, which makes it a genuinely solid foundation for a security-sensitive communication framework: the kernel itself is the arbiter of which process can send to which port, rather than relying on cooperating processes to police access themselves.
What XPC adds on top of raw Mach IPC
Working with raw Mach ports and messages directly is low-level and easy to get wrong — manual message construction, port rights management, and serialization are all things a developer would otherwise have to handle correctly by hand. XPC wraps this in a much higher-level API: structured, dictionary-like messages (XPC objects) that serialize and deserialize automatically, connection objects that manage the underlying Mach port lifecycle, and — critically for security — automatic handling of connection validation, so a service can straightforwardly verify who’s actually connecting to it before trusting anything in the message.
Why this matters for sandboxing specifically
macOS’s App Sandbox restricts what a sandboxed application can directly do — access arbitrary files, reach arbitrary network hosts, control other processes — and XPC is the mechanism that lets a sandboxed app still get privileged work done without simply punching holes in its own sandbox to do it directly. Instead, the sandboxed app talks over XPC to a separate, unsandboxed (or differently-privileged) helper process or system service, which performs the actual privileged operation and returns just the result. The sandboxed app’s own process never gains the broader privilege itself — it just receives the outcome of an operation performed by something else that has it.
The security boundary this creates
This pattern — a tightly scoped, single-purpose XPC service doing one specific privileged thing on behalf of less-privileged callers — is deliberately different from simply granting broad privilege to a large, general-purpose process. If an XPC service is compromised, the damage is bounded by exactly what that specific service was designed to do, not by whatever the calling application could otherwise reach. This is why macOS system architecture tends toward many small, single-purpose XPC services rather than a few large, broadly-privileged daemons — it’s a direct, deliberate application of the principle of least privilege at the process-architecture level, not just at the file-permission level.
Where developers actually see this
Any macOS app using system frameworks for privileged operations — printing, certain camera or microphone access flows, background app extensions — is very likely going through an XPC-based service under the hood, whether or not the developer explicitly wrote any XPC code themselves; a great deal of Apple’s own system frameworks use XPC internally to reach privileged system services on the calling application’s behalf, entirely transparently. Developers building their own privilege-separated app architecture (a sandboxed main app plus a separate, differently-entitled helper) use the NSXPCConnection/xpc_connection_t APIs directly, which handle the connection lifecycle, message serialization, and basic validation automatically rather than requiring manual Mach port management.
Why this design has held up
The core idea — cheap, kernel-mediated, structured message passing as the connective tissue between deliberately narrow, single-purpose privileged services — has scaled from its original use inside macOS itself to become the standard pattern Apple recommends for third-party app architecture as sandbox and entitlement requirements have tightened over time. It’s a clear case of an IPC mechanism originally built for one specific internal purpose (letting Mach’s microkernel-derived IPC serve XNU’s actual privilege-separation needs) turning out to generalize well to an entire platform’s approach to secure inter-process communication, years after the underlying Mach IPC primitives were first designed.