Blocking USB Devices on macOS – DriverKit or Other Recommended Approach

Hi Apple,

We are working on a general USB device management solution on macOS for enterprise security. Our goal is to enforce policy-based restrictions on USB devices, such as:

For USB storage devices: block mount, read, or write access.

For other peripherals (e.g., USB headsets or microphones, raspberry pi, etc): block usage entirely.

We know in past, kernel extension would be the way to go, but as kext has been deprecated. And DriverKit is the new advertised framework.

At first, DriverKit looked like the right direction. However, after reviewing the documentation more closely, we noticed that using DriverKit for USB requires specific entitlements:

DriverKit USB Transport – VendorID

DriverKit USB Transport – VendorID and ProductID

This raises a challenge: if our solution is meant to cover all types of USB devices, we would theoretically need entitlements for every VendorID/ProductID in existence.

My questions are:

Is DriverKit actually the right framework for this kind of general-purpose USB device control?

If not, what framework or mechanism should we be looking at for enforcing these kinds of policies?

We also developed an Endpoint Security product, but so far we haven’t found a relevant Endpoint Security event type that would allow us to achieve this.

Any guidance on the correct technical approach would be much appreciated.

Thanks in advance for your help.

Answered by DTS Engineer in 859788022

So, my first suggestion here is that you get I/O Registry Explorer from our "Additional Tools for Xcode" download so you can actually see what's going on. The same information in text from is in the sysdiagnose (that's how I know what happened), but in my experience, I/O Registry Explorer makes the data much easier to understand. For reference, you'll almost always want to look at the "IOService" plane (the default), and you change planes using the pop-up button in the top left. Also, over time, registry activity has increased to the point where the app can laggy or have other interface glitches. For general "exploration", you can avoid those issues by saving the ioreg file, then opening the file again so you're working with static data.

Moving to the specific issue:

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, the keyboard works without changes. I can see in the console that my deny was received.

Yes. You received and denied three auth requests. You were then notified of three events, from two processes.

Case 1-> pid=469, /usr/libexec/airportd:

[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23
	- I(pid=469, path=/usr/libexec/airportd, ppid=1, 
	team_id=(null)), T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, 
RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000
	/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK

To be honest, I'm not sure what's going on here, but I suspect there's an issue with what's being logged. airportd does have user clients open (12 to be exact), but none of them are tied to that device or even USB. My best guess is that you're either being notified of the same request you failed or there's something wrong with your logging; however, either way, this isn't why the keyboard works.

Case 2-> pid=430, path=/System/.../WindowServer

[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 
   - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, 
   team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, 
RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000
   /USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
   /IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK

The WindowServer is the process that actually receives HID activity from the kernel and turns it into the "events" that applications receive and process. The open went through because you didn't block it, probably because the process was muted (either by you or because the WindowServer is on the default mute list). If you unmute the process and deny the open, the keyboard won't work.

Covering a few other details, it's worth noticing that the connections here are happening at very different levels of the system— you denied at the USB level ("AppleUSBHostDeviceUserClient"), but the WindowServer is connecting through HID ("IOHIDEventServiceUserClient"). That's relevant because the different user client levels have very different roles and capabilities. Ironically, the USB device user client (what you blocked) doesn't actually "do" very much— it exists so a process can attach to a particular device and acquire exclusive access, but actually "doing" something with the device generally means connecting to an interface, which I believe would have triggered a new auth request for the interface to open.

As a side note here, if you choose to unmute the WindowServer, be VERY careful when choosing what to actually block. By my count, it has 147 user client connections, most of which are very likely critical to general system function. Blocking the wrong connections is very likely to cripple your system and/or panic the kernel.

Next, I have to ask "what are you actually trying to do?“ There are actually two different issues with blocking HID devices:

  1. The HID specification is widely used as a software control/configuration interface, not just for "keyboards and mice". This is not an abstract edge case as, by my count, there are 131 separate IOHIDEventServiceUserClient's active on your test machine, most of which are obviously not "Human Interface Devices".

  2. If your actual goal here is to prevent/control how input enters the system, then IOKit can only block one very specific pathway among many. To start with, the Bluetooth stack is largely implemented in user space, NOT the kernel. I believe the current implementation works by creating an "artificial" HID device in the kernel (so blocking might still work), but nothing requires it to work this way, given that most of its implementation is already outside the kernel. However, the bigger issue is that the WindowServer itself has its own event API which will completely bypass all of this.

If your goal is to block/control input, then I think the only real option is to use CGEventTap to directly interact with the event stream. If you try to do it below that layer, I think you'll find that there are simply too many other edge cases and side channels to try and predict and cover. Note that moving to the higher level also means using an agent running in the user session instead of a daemon running "system wide".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

We are working on a general USB device management solution on macOS for enterprise security. Our goal is to enforce policy-based restrictions on USB devices, such as: For USB storage devices: block mount, read, or write access.

For other peripherals (e.g., USB headsets or microphones, Raspberry Pi, etc.): block usage entirely. We know in the past, kernel extensions would be the way to go, but as kext has been deprecated. And DriverKit is the new advertised framework.

At first, DriverKit looked like the right direction. However, after reviewing the documentation more closely, we noticed that using DriverKit for USB requires specific entitlements: DriverKit USB Transport – VendorID DriverKit USB Transport – VendorID and ProductID

This raises a challenge: if our solution is meant to cover all types of USB devices, we would theoretically need entitlements for every VendorID/ProductID in existence.

My questions are: Is DriverKit actually the right framework for this kind of general-purpose USB device control?

No. Three issues:

(1) There are a bunch of low-level technical issues that would interfere with this. For example, DEXTs load "late" relative to KEXTs, which is going to create race conditions between your DEXT loading and other processes claiming the hardware. Deciding what to block is also harder than you think, as your DEXT doesn't have access to any kind of "storage" (so you can't have a simple "do not block" list) and determining what a device actually is at the level your blocking is hardware than it looks (that is, a "keyboard" and a "hard drive" both "look" identical at the USB interface level).

(2) You're welcome to apply, but this will not be approved:

This raises a challenge: if our solution is meant to cover all types of USB devices, we would theoretically need entitlements for every VendorID/ProductID in existence.

We actually have a "match everything" entitlement, as that’s how the "Development Only" entitlement variant works. However, one of the basic goals of the DriverKit architecture was to better constrain DEXT matching (vs IOKit) so that an arbitrary driver could claim "any" device. We let the "Development Only" entitlement variant "match anything" specifically because:

  1. It's ENORMOUSLY useful to DEXT developers. For example, it's very common for development/testing boards to use the VID/PID of the hardware manufacturer (not whatever the shipping product will be) and the dev only entitlement means developers can easily use this hardware without any unnecessary.

  2. The behavior and limitation of development signing make it wildly impractical to use for any kind of broad distribution. The total machine count is relatively small and the build expiration time is relatively short and non-obvious, both of which would make it a real pain to distribute software with. That's a very narrow and specialized exception. I don't expect us to ever approve that configuration for broader distribution, as DriverKit was designed around NOT working this way.

  3. Even if you were able to resolve both those issues, it wouldn't actually provide a "full" solution. The problem you overlooked here is that your DEXT is also in "competition" with DEXTs (and other system components) for control of that device. In the case of DEXTs, any device-specific DEXT would supersede your DEXT because that's what the USB specification rules for driver prioritization require. In addition, the IOUSBHost framework is capable of loading "underneath" your DEXT, forcing it to unload and ceding control to the other process. There are ways you could mitigate these issues, but any mechanism that could protect against these cases can just as easily protect the interface "directly".

If not, what framework or mechanism should we be looking at for enforcing these kinds of policies?

Well, the best answer is right here:

We also developed an Endpoint Security product, but so far we haven’t found a relevant Endpoint Security event type that would allow us to achieve this.

There are basically two cases you're concerned with here:

(1) IOKit User Clients.
You can block these with ES_EVENT_TYPE_AUTH_IOKIT_OPEN, which is FABULOUSLY more useful starting in macOS 26. The new data means you can determine exactly what hardware is involved and block whatever you want.

(2) Through the file system, both as device nodes and through mounts.

The ES system already has the tools for blocking these, either by blocking the device node from opening or by blocking the mount itself. As a side note here, if you're going to be blocking mounts, then I strongly recommend implementing your initial block using DiskArb, with the ES system acting as a "backstop" if DiskArb is bypassed. This post has a more complete write-up, but the short summary is that blocking through DiskArb will reduce the load on your ES client while also providing a better overall user experience (vs. failing the mount directly through ES).

Finally, keep in mind that USB isn't the only storage bus. Thunderbolt, NVMe, and SATA are common, not to mention rarer cases like SAS or SCSI. Trying to block at the bus level means having to predict every possibility and coming up with a unique approach to block each bus, many of which can't easily be blocked. Blocking at the storage layer lets you ignore those issues and block "everything".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin

Thank you for you reply.

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, keyboard works without changes. I can see it console that my deny was received.

The events from a keyboard:

[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=10, global_seq_num=20 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=10, global_seq_num=20[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=11, global_seq_num=21 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=11, global_seq_num=21[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=10, global_seq_num=22 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK
[2025-08-06 20:53:54.777964868] [1754513634777] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=13, global_seq_num=25 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578475, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@1/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver

Regards,

keefo

Hi Kevin

Thank you for you reply.

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, keyboard works without changes. I can see it console that my deny was received.

The events from a keyboard:

[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=10, global_seq_num=20 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=10, global_seq_num=20[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=11, global_seq_num=21 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=11, global_seq_num=21[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=10, global_seq_num=22 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK
[2025-08-06 20:53:54.777964868] [1754513634777] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=13, global_seq_num=25 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578475, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@1/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver

Hi Kevin

Thank you for you reply.

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, keyboard works without changes. I can see it console that my deny was received.

The events from a keyboard:

[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=10, global_seq_num=20 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=10, global_seq_num=20[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=11, global_seq_num=21 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=11, global_seq_num=21[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=10, global_seq_num=22 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK
[2025-08-06 20:53:54.777964868] [1754513634777] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=13, global_seq_num=25 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578475, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@1/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver

Hi Kevin

Thank you for you reply.

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, keyboard works without changes. I can see it console that my deny was received.

The events from a keyboard:

[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=10, global_seq_num=20 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=10, global_seq_num=20[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_AUTH_IOKIT_OPEN == 91, v=10, seq_num=11, global_seq_num=21 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
**** Sending ES_AUTH_RESULT_DENY **** seq_num=11, global_seq_num=21[2025-08-06 20:53:54.668478952] [1754513634668] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=10, global_seq_num=22 - I(pid=365, path=/usr/sbin/systemstats, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23 - I(pid=469, path=/usr/libexec/airportd, ppid=1, team_id=(null)),T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK
[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK
[2025-08-06 20:53:54.777964868] [1754513634777] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=13, global_seq_num=25 - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578475, RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000/IOUSBHostInterface@1/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver

So, my first suggestion here is that you get I/O Registry Explorer from our "Additional Tools for Xcode" download so you can actually see what's going on. The same information in text from is in the sysdiagnose (that's how I know what happened), but in my experience, I/O Registry Explorer makes the data much easier to understand. For reference, you'll almost always want to look at the "IOService" plane (the default), and you change planes using the pop-up button in the top left. Also, over time, registry activity has increased to the point where the app can laggy or have other interface glitches. For general "exploration", you can avoid those issues by saving the ioreg file, then opening the file again so you're working with static data.

Moving to the specific issue:

We have test ES_EVENT_TYPE_AUTH_IOKIT_OPEN on 26, and it does not block anything. We report the same issue in FB19420236.

I can see AUTH requests coming from system stats and airportd processes, I can deny them, yet when I plug a keyboard and do it, the keyboard works without changes. I can see in the console that my deny was received.

Yes. You received and denied three auth requests. You were then notified of three events, from two processes.

Case 1-> pid=469, /usr/libexec/airportd:

[2025-08-06 20:53:54.669013579] [1754513634669] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=11, global_seq_num=23
	- I(pid=469, path=/usr/libexec/airportd, ppid=1, 
	team_id=(null)), T=1, C=AppleUSBHostDeviceUserClient, RID=4305578448, 
RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000
	/USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
  parent_registry_id=4305578448
    | name = Gaming Keyboard | 04F3:2014 | OK

To be honest, I'm not sure what's going on here, but I suspect there's an issue with what's being logged. airportd does have user clients open (12 to be exact), but none of them are tied to that device or even USB. My best guess is that you're either being notified of the same request you failed or there's something wrong with your logging; however, either way, this isn't why the keyboard works.

Case 2-> pid=430, path=/System/.../WindowServer

[2025-08-06 20:53:54.755309056] [1754513634755] ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN == 24, v=10, seq_num=12, global_seq_num=24 
   - I(pid=430, path=/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources/WindowServer, ppid=1, 
   team_id=(null)),T=1702065507, C=IOHIDEventServiceUserClient, RID=4305578467, 
RPATH=IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/usb-drd0@82280000/AppleT8103USBXHCI@00000000/usb-drd0-port-hs@00100000
   /USB2.0 Hub@00100000/AppleUSB20Hub@00100000/AppleUSB20HubPort@00140000/Gaming Keyboard@00140000
   /IOUSBHostInterface@0/AppleUserUSBHostHIDDevice/IOHIDInterface/AppleUserHIDEventDriver
  parent_registry_id=4305578467
    | name = AppleUserHIDEventDriver | 0000:0000 | OK

The WindowServer is the process that actually receives HID activity from the kernel and turns it into the "events" that applications receive and process. The open went through because you didn't block it, probably because the process was muted (either by you or because the WindowServer is on the default mute list). If you unmute the process and deny the open, the keyboard won't work.

Covering a few other details, it's worth noticing that the connections here are happening at very different levels of the system— you denied at the USB level ("AppleUSBHostDeviceUserClient"), but the WindowServer is connecting through HID ("IOHIDEventServiceUserClient"). That's relevant because the different user client levels have very different roles and capabilities. Ironically, the USB device user client (what you blocked) doesn't actually "do" very much— it exists so a process can attach to a particular device and acquire exclusive access, but actually "doing" something with the device generally means connecting to an interface, which I believe would have triggered a new auth request for the interface to open.

As a side note here, if you choose to unmute the WindowServer, be VERY careful when choosing what to actually block. By my count, it has 147 user client connections, most of which are very likely critical to general system function. Blocking the wrong connections is very likely to cripple your system and/or panic the kernel.

Next, I have to ask "what are you actually trying to do?“ There are actually two different issues with blocking HID devices:

  1. The HID specification is widely used as a software control/configuration interface, not just for "keyboards and mice". This is not an abstract edge case as, by my count, there are 131 separate IOHIDEventServiceUserClient's active on your test machine, most of which are obviously not "Human Interface Devices".

  2. If your actual goal here is to prevent/control how input enters the system, then IOKit can only block one very specific pathway among many. To start with, the Bluetooth stack is largely implemented in user space, NOT the kernel. I believe the current implementation works by creating an "artificial" HID device in the kernel (so blocking might still work), but nothing requires it to work this way, given that most of its implementation is already outside the kernel. However, the bigger issue is that the WindowServer itself has its own event API which will completely bypass all of this.

If your goal is to block/control input, then I think the only real option is to use CGEventTap to directly interact with the event stream. If you try to do it below that layer, I think you'll find that there are simply too many other edge cases and side channels to try and predict and cover. Note that moving to the higher level also means using an agent running in the user session instead of a daemon running "system wide".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Blocking USB Devices on macOS – DriverKit or Other Recommended Approach
 
 
Q