Behaving as designed

The finding I was most confident about — fskitd missing an entitlement check on formatResource and activateVolume — came back as expected behaviour. A note on what that means, and what it taught me about the difference between a security gap and a design choice.


In the dot-com years I spent time in Budapest, building networks for the internet hotel era. The data centre we used there had armed guards. Serious ones — AK-47s, not the decorative kind. My first visit I assumed this meant the facility was impenetrable. It took a while to understand that the guards were there to protect the building, not to verify whether any given person was authorised to access any given rack. Their presence was real. Their scope was different from what I had assumed.

This is a note about a finding that went the same way.

The finding

fskitd — the file system kit daemon — is the system process that hosts third-party file system extensions on macOS. When a file system extension needs to perform an operation (format a volume, check a volume's integrity, probe a device, activate a volume for mounting), the request routes through fskitd.

These operations — formatResource, checkResource, probeResource, activateVolume — are significant. They can reformat storage, modify volume structures, or mount file systems. The developer documentation describes them as requiring the com.apple.developer.fs-kit.extension entitlement. On that basis I expected the daemon to enforce that entitlement at the IPC boundary before allowing any caller to invoke them.

On my test hardware, an unprivileged process — uid=501, no entitlements — could reach the fskitd XPC interface and invoke these methods. The daemon did not return an entitlement-denied error at the IPC gate. The calls proceeded into fskitd's handler code.

Tested on
macOS 26.4.1 (25E253) · arm64e · own hardware and UTM VM · uid=501, no entitlements · DTrace + XPC probe · no third-party systems

I submitted this to Apple's Security Bounty programme, framed as a missing entitlement check on privileged file system operations accessible to unprivileged callers. The report went into review. For a period it carried a "Fix scheduled — Summer 2026" status. I considered it the strongest report in my active portfolio.

The PoC

#!/bin/bash
# fskitd entitlement gate probe — uid=501, no entitlements
# Own hardware only. Demonstrates IPC reachability.
# Apple confirmed: expected behaviour. The operations are intentionally
# accessible without the developer entitlement from the system side.

# DTrace probe (SRDP hardware / partial SIP disable):
# sudo dtrace -n '
#   objc$target:FSKitServer:-*Resource*:entry,
#   objc$target:FSKitServer:-*Volume*:entry,
#   objc$target:FSKitServer:-activate*:entry
#   { printf("fskitd method called: %s  uid=%d\n", probefunc, uid); }'
#   -p $(pgrep fskitd)

# XPC reachability — public FSKit framework:
cat <<'SWIFT'
import FSKit
import Foundation

// Attempt to reach fskitd operations from unprivileged caller
let url = URL(fileURLWithPath: "/dev/disk2")
let task = FSTaskDescription()
task.url = url

// probeResource — should require com.apple.developer.fs-kit.extension
// In practice: reaches the handler; returns meaningful FSError, not entitlement-denied
FSKitVersion.current  // confirms framework loaded
print("FSKit loaded. fskitd reachable from uid=501 without entitlement.")
print("Return value is a filesystem NSError (operation context), not EPERM.")
SWIFT

echo ""
echo "The distinction: reaching the handler ≠ exploiting the operation."
echo "The operation itself fails safely — the entitlement controls what"
echo "a developer-registered extension is allowed to do, not who can probe."

Apple's response

The closure came with a characterisation I had not anticipated:

Expected behaviour.

Two words, but they carry weight. Apple's security team reviewed the finding with knowledge of the full architecture, and their conclusion was that the entitlement gate in the documentation describes a developer-facing restriction — what a registered file system extension is permitted to do — not a restriction on who can invoke the IPC interface to probe for extensions. The operations fail safely for callers without a registered extension; the gate is on the extension side, not the caller side.

What this means

I had read the entitlement requirement as a boundary on access to the operation. Apple's design positions it as a boundary on the capability of the operation — specifically, whether a registered extension will respond. The difference is architectural.

An analogy from Budapest: the AK-47 guards controlled entry to the building. Whether you could access a specific rack inside depended on different controls entirely — cage locks, customer credentials, the hosting agreement. The guards' presence did not mean the rack-level access model was what I assumed it to be.

The fskitd entitlement gate works similarly. com.apple.developer.fs-kit.extension controls whether an extension is registered and trusted to handle file system operations — not whether an arbitrary caller can reach the daemon's probe interface. The probe interface is reachable; what it can do to registered volumes is what the entitlement constrains.

The practical implication
An unprivileged caller reaching the fskitd XPC interface can invoke the probe and check methods. It receives meaningful errors rather than silent failures. What it cannot do is invoke a trusted file system extension's actual implementation — because that requires the extension to be registered, and registration requires the entitlement. The caller gets as far as the front desk; it does not get into the server room.
Opinion, clearly flagged: I think the documentation could be clearer about where the entitlement gate operates — whether at the IPC boundary or at the extension-capability layer. A researcher reading the documentation reasonably concludes the former. Apple's design intends the latter. Both things can be true simultaneously: the design is defensible and the documentation gap is real. In my view the closure is correct; a documentation improvement would prevent the same question being asked again.

The lesson in confidence

This was the report I was most confident about. It went into "reviewing" and then carried a fix-scheduled status for a period, which I read as validation. The eventual closure as expected behaviour was a useful reminder that fix-scheduled status reflects Apple's internal process state, not their final assessment of whether something is a vulnerability. The two can diverge.

I had found the architectural asymmetry correctly. I had interpreted what it meant incorrectly. Confidence in the observation and confidence in the interpretation are different things, and I had collapsed them into one.

The guards were there. They were guarding something. It was not what I thought they were guarding.

Are you there, fskitd? Yes — and so is anyone who wants to knock. What matters is what happens when the door opens.