Virtual Machine UDID Changes in macOS 15: Looking for Guidance on Development Workflow

Hello,

We're developing endpoint security software using the Endpoint Security framework, and we've encountered challenges with the behavior change in macOS 15 regarding provisioning UDIDs in cloned VMs.

The Change

Prior to macOS 15, cloning a VM preserved its UDID (format: 0000FE00-9C4ED9F68BBDC72D). Starting with macOS 15, cloned VMs receive a new UDID generated from the host's Secure Enclave (format: b043d27202c7ac37ca3c6b82673302225485cae9), making each clone effectively a new device.

Our Workflow

We maintain a clean base VM image and clone it for each test run. We add the base VM's UDID to our provisioning profile once, then create clones which (previously) retained that same UDID, allowing us to start new testing cycles without re-registering devices. This is essential because our product involves low-level system integration through the Endpoint Security framework, and if something goes wrong during development, it has the potential to affect system stability. To prevent any cascading issues between test runs or different product versions, we need each test to start from a known clean state rather than reusing the same VM.

The Challenge

With each VM clone generating a new UDID, we're hitting Apple's device registration limits quickly. This particularly impacts:

  • New team members who spin up VMs for the first time and can't run signed builds
  • Our CI/CD pipeline where multiple test environments need provisioning profiles
  • Developers testing different branches who need separate clean environments

Current Workaround

We've found that VMs created on macOS 14 and upgraded to macOS 15+ retain their original UDID format. However, we're concerned this workaround may stop working in future macOS versions, which would leave us without a viable path forward.

If the workaround stops working, our fallback would be signing each CI build with a Developer ID signature to allow running on any device. However, we'd prefer to avoid this as it would significantly increase load on Apple's signing infrastructure for what are essentially internal test builds.

We completely understand the security reasoning behind tying UDIDs to the host's Secure Enclave for Apple Account support. However, for development workflows that don't require Apple Account features in VMs but do require clean, isolated test environments, the previous behavior was quite valuable.

Question

Is there a recommended approach for teams in our situation? We're happy to explore alternative workflows if there's a pattern we're missing, or we'd be glad to provide more context if this is a use case Apple is considering for future updates.

Thanks for any guidance you can provide!

Feedback case: FB21389730

How are you cloning these VMs? Specifically, are you calling Virtualization framework from your own code? Or is your infrastructure relying on VM infrastructure provided by another third party?

Share and Enjoy

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

We are using an open-source project called UTM (https://github.com/utmapp/UTM) for managing our virtual machine infra. The way how cloning works in our current workflow is by taking an existing visual machine (a UTM bundle file) and copying it with cp command and updating the metadata to avoid clashes with existing virtual machines like so

cp -cR "$template_file" "$clone_file"
xmlstarlet ed --inplace -u '//key[.="Name"]/following-sibling::string[1]' -v "$clone_name" "${clone_file}/config.plist"
xmlstarlet ed --inplace -u '//key[.="MacAddress"]/following-sibling::string[1]' -v "$new_mac_address" "${clone_file}/config.plist"

After that, the newly copied virtual machine file is opened with UTM app with open command

open -a "UTM" "$clone_file"

It appears in the list of registered virtual machines and it's booted up. So I suspect that the UTM app is just opening the virtual machine and treating it as a separate entity. However, this approach allowed us to preserve provisioning UDID so far.

There is one curious detail that we noticed a few days ago. We tried to reproduce the behavior where provisioning UDID was not getting preserved when following the steps above. However, it now behaves as expected and preserves the provisioning UDID with the same steps as before.

We did not manage to pinpoint what exactly causes the difference in behavior now. Previously, we were able to observe the unexpected behavior on 3 different hosts. We'll keep monitoring and will see if we manage to stumble upon the issue again.

So probably at the moment the main question would be about the recommended way to clone a virtual machine and preserve provisioning UDID?

What to look out for and make sure we use appropriate approach to be aligned with the expectations of the Virtualization framework?

I hope the expectation of preserving of the provisioning UDID when cloning a virtual machine is valid on our side.

Virtual Machine UDID Changes in macOS 15: Looking for Guidance on Development Workflow
 
 
Q