Is suspended spawn + audit_token_t matching a supported security boundary for one exact macOS process occurrence?

I’m designing a macOS privileged-service boundary and I’d like to clarify whether a process-occurrence authentication pattern previously described by Apple DTS is a supported shipping security contract, rather than just behaviour that happens to work on current macOS. Target: current macOS 26.x, using public APIs only. Threat model An arbitrary hostile process may run as the same ordinary, non-admin login user as the application. The attacker can launch an exact second copy of the legitimately signed requester binary. The attacker cannot obtain administrator / Touch ID authorization and does not control root, SIP, Recovery, the kernel, or the code-signing infrastructure. Desired property After a fresh Human-authorized operation, a root LaunchDaemon should grant authority to one specific requester process occurrence, not to every process having the same code-signing identity. Apple DTS thread 842442 describes a pattern based on:

  1. launching the requester suspended with posix_spawn(..., POSIX_SPAWN_START_SUSPENDED);
  2. obtaining a name/task port for that process;
  3. reading its TASK_AUDIT_TOKEN;
  4. resuming the process; and
  5. accepting only Mach messages whose kernel audit trailer identifies that same process occurrence.

Thread 842442 also describes this area as being on “thin compatibility ice”, which is why I do not want to build a security boundary on behaviour that Apple does not intend applications to rely on. My core question is: Can a shipping macOS application rely on a pre-bound audit_token_t obtained from a suspended child and compare it against the audit token in subsequent raw Mach message trailers as a supported security boundary for that exact process occurrence? In particular, I need to know whether the supported contract covers:

  • distinguishing another process with the exact same signed executable;
  • PID reuse after the original process exits;
  • messages queued before or around sender termination;
  • a Mach send right transferred to another process — does the receiver see the audit token of the process that actually sends each message?;
  • later exec by the original process; and
  • whether full audit_token_t equality is an appropriate supported comparison for this purpose.

If that is not a supported shipping contract, is there a current public XPC API that provides the equivalent property: binding one privileged-service session to one exact process occurrence rather than merely to its code-signing identity? I’m specifically trying to distinguish: code identity = this is an approved executable from mission authority = this one particular authorized process occurrence I’m happy with a negative answer if macOS does not expose a stable public contract for the latter. Related Apple DTS discussion: https://developer.apple.com/forums/thread/842442

Answered by DTS Engineer in 905537022

Jumping in on this...

Is that essentially the use case you had in mind when pointing me to es_new_descendants_client?

What you're describing here:

The product is a local macOS application that coordinates AI-assisted software development work.

...is one of the primary use cases es_new_descendants_client was designed for.

Can it be used to ensure that only a selected descendant subtree may obtain/connect to a particular privileged XPC/Mach service, while another same-UID process running identical signed code outside that subtree cannot?

Your level of control is bound to your descendants, so you'll only see the actions of your children. However, you have full control over your children's activities.

Also, one thing to note is that the es_new_descendants_client does NOT have the same deadline limitations as the standard ES client, which DRAMATICALLY simplifies many approvals. For example, if you want the user permission for a particular exec, you can just ask the user and not approve the auth until the user consents. From the calling processes perspective, they'll just block in exec until you approve or deny.

After an allowed descendant obtains the endpoint/send right, is delegation of that endpoint/right to a non-descendant something this mechanism prevents or detects, or would I still need another boundary for that?

No, the API only applies to your descendants. However, I also think this kind of much broader activity is much more difficult to detect and properly control, very quickly pushing you back into full ES client territory. That may be valid, but I think it needs to be understood as a separate problem set with a different set of solutions.

Finally, would the Endpoint Security client entitlement be considered appropriate for a broadly shipped developer tool whose use of ES is specifically to enforce this per-operation authority boundary, rather than for a traditional endpoint-security product?

I don't know where things stand here, but the intention is that es_new_descendants_client can be used much more broadly than the ES API. In practice, that will probably mean a new self-add entitlement (meaning, you don't need our specific approval).

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Are you working on the same product as the user hjvoryn in that older thread?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, it’s the same product and the same underlying security requirement. I opened this new thread because the earlier answer established that suspended posix_spawn + TASK_AUDIT_TOKEN + Mach audit trailers is technically possible, but also described that approach as being on “very thin compatibility ice”. For a security boundary in a product intended to ship to users, I don’t think I can treat that as a sufficiently stable platform contract. What I’m trying to determine now is whether macOS offers a supported public architecture for granting authority to one exact requester process occurrence, even when another same-UID process can launch an identical signed copy. If the audit-token composition is not suitable as a supported shipping boundary, is there another public mechanism or architecture Apple recommends for this threat model? If macOS simply does not provide that guarantee today, confirmation of that would also be extremely useful. es_new_descendants_client is interesting, but my requirement is not primarily descendant tracking; it is authenticating the exact requester occurrence that was freshly authorized.

My “thin compatibility ice” comment refers to this entire task. To escape that you’d have to not use Mach messaging directly, and you’ve already established that that’s a requirement.

To give you a better answer I need more information about this:

For a security boundary in a product intended to ship to users

What sort of product is this? Why high-level goal are you trying to achieve?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn. The product is a local macOS application that coordinates AI-assisted software-development work. Some operations may ultimately cause privileged or otherwise security-sensitive effects, so we need to preserve a very specific authority boundary between a Human-approved operation and the process that is allowed to exercise that authority. The high-level requirement is: A user explicitly authorizes one operation. After that authorization, we want a privileged service to accept security-sensitive requests only from the exact requester process occurrence that was created for that operation. Another process running as the same login user must not be able to inherit or replay that authority merely by launching the same signed executable or by obtaining access to a reusable IPC endpoint. We are not trying to protect against root, kernel compromise, SIP bypass, or an attacker who can obtain a new administrator / Touch ID authorization. The attacker we care about is another arbitrary process running as the same ordinary user. The reason I was exploring the suspended-spawn / audit-token / Mach-message approach was to bind the Human authorization to that one process occurrence rather than to code identity alone. If macOS does not expose a supported public way to make that distinction, that is useful information too. In that case I would rather redesign the product boundary than build a shipping security property on unsupported behaviour. So the architectural question is really: what is the supported macOS pattern, if any, for granting a freshly authorized capability to one exact requester occurrence while excluding another same-UID process running identical signed code?

Thanks for those details; most helpful!

In the previous thread I mentioned the new Endpoint Security feature that’s kinda designed for this task. Have you explored that option? Did you run into some sort of blocker?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn. I hadn’t evaluated es_new_descendants_client as the primary architecture yet, mainly because the original target was macOS 26.x and I had been looking at the older Endpoint Security / process-identity mechanisms rather than treating the new descendants client as the authority boundary. Having now looked at it more closely, it does seem much closer to the actual requirement. I can structure the product so that, after the Human authorizes an operation, Anvil launches a dedicated per-operation worker as a descendant of a process that owns a descendants-scoped ES client. I do not need arbitrary independently launched processes to acquire this authority. If the intended pattern is that the descendants client can authorize only that subtree’s access to a privileged service, for example by governing BOOTSTRAP_LOOK_UP / XPC_CONNECT, that may let me avoid raw Mach messaging and the suspended-spawn/audit-token composition entirely, which would be preferable. Before I pursue that architecture, I have four points I’d like to clarify:

  • Is that essentially the use case you had in mind when pointing me to es_new_descendants_client?
  • Can it be used to ensure that only a selected descendant subtree may obtain/connect to a particular privileged XPC/Mach service, while another same-UID process running identical signed code outside that subtree cannot?
  • After an allowed descendant obtains the endpoint/send right, is delegation of that endpoint/right to a non-descendant something this mechanism prevents or detects, or would I still need another boundary for that?
  • Finally, would the Endpoint Security client entitlement be considered appropriate for a broadly shipped developer tool whose use of ES is specifically to enforce this per-operation authority boundary, rather than for a traditional endpoint-security product?

The macOS 27 minimum-version issue is something I can evaluate separately. If this is the supported architectural direction going forward, I would much rather design around it than ship the kernel-coupled Mach/audit-token approach.

Accepted Answer

Jumping in on this...

Is that essentially the use case you had in mind when pointing me to es_new_descendants_client?

What you're describing here:

The product is a local macOS application that coordinates AI-assisted software development work.

...is one of the primary use cases es_new_descendants_client was designed for.

Can it be used to ensure that only a selected descendant subtree may obtain/connect to a particular privileged XPC/Mach service, while another same-UID process running identical signed code outside that subtree cannot?

Your level of control is bound to your descendants, so you'll only see the actions of your children. However, you have full control over your children's activities.

Also, one thing to note is that the es_new_descendants_client does NOT have the same deadline limitations as the standard ES client, which DRAMATICALLY simplifies many approvals. For example, if you want the user permission for a particular exec, you can just ask the user and not approve the auth until the user consents. From the calling processes perspective, they'll just block in exec until you approve or deny.

After an allowed descendant obtains the endpoint/send right, is delegation of that endpoint/right to a non-descendant something this mechanism prevents or detects, or would I still need another boundary for that?

No, the API only applies to your descendants. However, I also think this kind of much broader activity is much more difficult to detect and properly control, very quickly pushing you back into full ES client territory. That may be valid, but I think it needs to be understood as a separate problem set with a different set of solutions.

Finally, would the Endpoint Security client entitlement be considered appropriate for a broadly shipped developer tool whose use of ES is specifically to enforce this per-operation authority boundary, rather than for a traditional endpoint-security product?

I don't know where things stand here, but the intention is that es_new_descendants_client can be used much more broadly than the ES API. In practice, that will probably mean a new self-add entitlement (meaning, you don't need our specific approval).

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks Kevin, this is extremely helpful and materially changes the direction I was considering. It sounds like the descendants client is much closer to the supported boundary I actually need than the suspended-spawn / raw Mach approach, especially given the lack of the standard ES deadline constraint. I’ll treat delegation outside the descendant subtree as a separate threat/problem rather than trying to stretch this API into solving it. My next step will be to prototype the narrower model: one Human-authorized operation, one descendant execution subtree, and descendant-scoped authorization of the sensitive actions that subtree can perform. I’ll also verify the macOS 27 deployment and entitlement requirements before treating this as a shippable architecture. Thanks again, this gives me a much clearer supported direction.

Thanks Kevin, your guidance materially changed the direction I’m looking at. I’ve now done a bounded pass over the public es_new_descendants_client semantics and I think the descendant-scoped model is the right supported foundation to explore. Before I prototype it, there are four details I’d like to clarify because they determine whether this can become a real authority boundary rather than just subtree policy:

  1. If a descendants client has a pending AUTH event and the ES client crashes, disconnects, or calls es_delete_client, what exact disposition applies to that blocked operation? Does FAIL_CLOSED cover client loss, or only deadline expiry / queue overflow?
  2. What exact operations generate AUTH_XPC_CONNECT? Is it limited to named Mach-service connections, or can it also cover connections established through transferred / anonymous XPC endpoints?
  3. From the XPC service side, is there a supported way to obtain sender identity or audit-token evidence per connection or per message, so the service could reject a transferred endpoint/connection originating from outside the approved descendant subtree?
  4. On distribution: is the descendants-client entitlement still expected to become self-service, and is a normal Developer ID app/helper using the currently managed Endpoint Security entitlement considered an intended production packaging model today?

I’m deliberately treating delegation outside the descendant subtree as a separate problem set, as you suggested, rather than trying to stretch the descendants API into solving everything. If these points line up, my next step would be a very narrow PoC: one Human-authorized operation, one descendant worker, and one harmless XPC connection gated through the descendants client with explicit Allow/Deny. Thanks again, this has been extremely helpful in narrowing the problem to a supported path.

  1. If a descendant client has a pending AUTH event and the ES client crashes, disconnects, or calls es_delete_client, what exact disposition applies to that blocked operation? Does FAIL_CLOSED cover client loss, or only deadline expiry / queue overflow?

If the client goes away, all the restrictions it applied are removed. This is an area the team is interested in improving, but that's the situation today.

What exact operations generate AUTH_XPC_CONNECT? Is it limited to named Mach-service connections, or can it also cover connections established through transferred / anonymous XPC endpoints?

This is something you'd need to test, but I suspect it’s just named connection.

From the XPC service side, is there a supported way to obtain sender identity or audit-token evidence per connection or per message, so the service could reject a transferred endpoint/connection originating from outside the approved descendant subtree?

No, I don't think so. There's an element here where the operations we allow to be blocked need to be scoped in ways that keep the system overall behavior "coherent". Blocking opens not really an issue, as apps understand they may not be able to open a file. Blocking read/write to an open file is a great way to corrupt file data.

A similar thing plays out here- there's a bit of a difference between blocking the initial connection between two processes vs. disrupting actions that are happening as part of the communication between two processes.

On distribution: is the descendants-client entitlement still expected to become self-service, and is a normal Developer ID app/helper using the currently managed Endpoint Security entitlement considered an intended production packaging model today?

Actually, this would be worth getting bugs filed about. If you have a moment, please file a bug asking us to provide a new entitlement for this, then post the bug number back here.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks Kevin. I’ve filed the enhancement request for a dedicated/self-service entitlement for es_new_descendants_client as you suggested. Feedback ID: FB24830531 I’ll treat the descendants client as descendant-action control while the client is alive, rather than as persistent custody of an IPC capability or a fail-closed authority boundary after client loss. I’ll keep the broader privileged-service / delegated-capability problem separate rather than trying to stretch this API beyond its intended boundary. Thanks again — this clarified the architecture considerably.

Is suspended spawn + audit_token_t matching a supported security boundary for one exact macOS process occurrence?
 
 
Q