I have a macOS VPN app with a Network Extension (packet tunnel provider) distributed outside the App Store via Developer ID. Everything works perfectly when running from Xcode. After archiving and exporting for Developer ID distribution, the extension launches but immediately gets killed by nesessionmanager.
The error: Signature check failed: code failed to satisfy specified code requirement(s) followed by: started with PID 0 status changed to disconnected, last stop reason Plugin failed
What makes this interesting: the extension process does launch. AMFI approves it, taskgated-helper validates the provisioning profile and says allowing entitlement(s) due to provisioning profile, the sandbox is applied, PacketTunnelProvider is created — but then Apple's Security framework internally fails the designated requirement check and nesessionmanager kills the session.
Key log sequence: taskgated-helper: Checking profile: Developer ID - MacOS WireGuardExtension taskgated-helper: allowing entitlement(s) for com.xx.xx.WireGuardNetworkExtension due to provisioning profile (isUPP: 1) WireGuardNetworkExtensionMac: AppSandbox request successful WireGuardNetworkExtensionMac: creating principle object: PacketTunnelProvider WireGuardNetworkExtensionMac: Signature check failed: code failed to satisfy specified code requirement(s) nesessionmanager: started with PID 0 error (null) nesessionmanager: status changed to disconnected, last stop reason Plugin failed
Setup:
- macOS 15, Xcode 16
- Developer ID Application certificate
- Manual code signing, Developer ID provisioning profiles with Network Extensions capability
- Extension in Contents/PlugIns/ (standard appex, not System Extension)
- Extension entitlement: packet-tunnel-provider-systemextension
- NSExtensionPointIdentifier: com.apple.networkextension.packet-tunnel
- codesign --verify --deep --strict PASSES on the exported app
- Hardened runtime enabled on all targets
What I've verified:
- Both app and extension have matching TeamIdentifier
- Both are signed with the same Developer ID Application certificate
- The designated requirement correctly references the cert's OIDs
- The provisioning profiles are valid and taskgated-helper explicitly approves them
- No custom signature validation code exists in the extension — the "Signature check failed" comes from Apple's Security framework
What I've tried (all produce the same error):
- Normal Xcode archive + export (Direct Distribution)
- Manual build + sign script (bypassing Xcode export entirely)
- Stripping all signatures and re-signing from scratch
- Different provisioning profiles (freshly generated)
Comparison with official WireGuard app: I noticed the official WireGuard macOS app (which works with Developer ID) uses packet-tunnel-provider (without -systemextension suffix) in its entitlements. My app uses packet-tunnel-provider-systemextension. However, I cannot switch to the non-systemextension variant because the provisioning profiles from Apple Developer portal always include the -systemextension variants when "Network Extensions" capability is enabled, and AMFI rejects the mismatch.
Questions:
- Is there a known issue with packet-tunnel-provider-systemextension entitlement + PlugIn-based Network Extension + Developer ID signing?
- Should the extension be using packet-tunnel-provider (without -systemextension) for Developer ID distribution? If so, how do I get a provisioning profile that allows it?
- The "Signature check failed" happens after taskgated-helper approves the profile — what additional code requirement check is the NE framework performing, and how can I satisfy it?
Any guidance would be appreciated. I've exhausted all signing approaches I can think of.