macOS App Sandbox Networking and Entitlements
Parent: Apple Platform Publishing (Mac App Store) · Published reference · snapshot 2026-10-02 · skill apple-platform-publishing/references/macos-app-sandbox-networking.md
Also known as: macOS App Sandbox networking for a Mac App Store network/DNS monitor: entitlements, Network.framework, Local Network privacy, interface-bound sockets, SMAppService, CoreWLAN, Developer ID twin build — verify against Apple docs and technotes (macOS 26-27, Oct 2026)
↓ Facts as markdownall context files
Source-anchored research for macOS App Sandbox Networking and Entitlements. Run status: COMPLETED.
These notes link each claim to its source. Some citations identify archived research reports that are no longer hosted on this site. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
Definitions
- Core WLAN is not supported in Mac Catalyst and NEHotspotNetwork is iOS-only. 'Mac (Designed for iPad)' strips sandbox entitlements. DTS says there is no good way to read the SSID there, so a native AppKit/SwiftUI-for-macOS target is required for an SSID feature. (low confidence) [source]
- Stapling only the DMG is not enough for offline first launch: once the app is copied out of the mounted DMG and the DMG is unmounted, the app has no ticket. An Apple engineer's guidance is to notarize and staple the app first, put it in the DMG, then notarize and staple the DMG. (medium confidence) [source]
Structure and components
- NWPathMonitor is part of Network.framework (iOS 12 / macOS 10.14+) and was introduced at WWDC 2018 as the replacement for SCNetworkReachability-style checks; Apple said it hoped all manual reachability uses would be replaced by the wait-for-connectivity model, with NWPathMonitor covering cases where that is insufficient. (medium confidence) [source]
How it works
- On macOS 27.0 CWInterface.ssid() and bssid() still return nil without Location authorization, while non-identifying data such as RSSI is returned. The fix reported is to add NSLocationWhenInUseUsageDescription to Info.plist, request Core Location authorization, then retry ssid(). Stats 3.0.17 shows SSID 'Unknown' on macOS 27 because it does none of this. (medium confidence) (verified as of 2026-09-23) [source]
- Command-line tools are unreliable for CoreWLAN SSID. On Sequoia 15.1.1 a CLI got nil SSID and BSSID from scanForNetworks with Location authorized, while the same code in a GUI app worked. DTS guessed the cause is run-loop behavior (a normal app runs the run loop continuously) and left it unresolved. (low confidence) (verified as of 2024-11-01) [source]
- Notarization is not App Review. Apps distributed through the Mac App Store need no notarization because App Store submission already includes equivalent checks; software built after June 1, 2019 and distributed with Developer ID must be notarized (macOS 10.15+). (high confidence) [source]
- When an app is both hardened and sandboxed, the restrictions stack: the app needs the entitlement each system requires (for example com.apple.security.automation.apple-events for the Hardened Runtime and a sandbox exception for Apple events). Missing either blocks the action. (low confidence) [source]
- Hardened Runtime entitlements are Boolean and default to false; Xcode embeds an entitlement only when true, and manual signers should follow that convention. Entitlements go only on executables; frameworks, shared libraries and in-process plug-ins inherit the host's entitlements. Apple's Hardened Runtime resource-access list covers camera, audio input, location, contacts, calendars, photos and Apple events, and does not list network access. (medium confidence) [source]
- Binding to the physical interface's IP with bind() makes traffic bypass a NetworkExtension-based VPN tunnel; Apple said in 2017 this is not a vulnerability because NetworkExtension makes no guarantee about traffic flow. Always-On VPN is not affected. (medium confidence) (verified as of 2017-12-19) [source]
- Inside a NEPacketTunnelProvider, setsockopt IP_BOUND_IF to the tunnel does not work because NECP prevents VPN loops (the call can succeed but data takes the default interface). This is irrelevant to a plain sandboxed monitor app. (low confidence) (verified as of 2022-09-01) [source]
- There is no general API to ask whether the process has local network access (FB8711182). Detect denial per operation: for Bonjour, an NWBrowser state .waiting(.dns(code)) with code kDNSServiceErr_PolicyDenied (-65570); for TCP, NWConnection enters .waiting and currentPath?.unsatisfiedReason == .localNetworkDenied. (low confidence) [source]
- macOS auto-allows launchd daemons, any process running as root, and command-line tools run from Terminal or SSH with their children. launchd agents and ordinary apps are not auto-allowed. For helpers, macOS attributes the operation to the responsible app and records the choice for the whole app; an agent not installed through SMAppService needs AssociatedBundleIdentifiers in its launchd plist. (low confidence) [source]
- On macOS there is no way to reset a program's Local Network privilege to Undetermined (FB14944392); workarounds are a VM snapshot or a fresh user account. There is no API to show the alert on demand; connecting a UDP socket to a link-local IPv6 address (port 9) triggers it without sending traffic, best effort. (low confidence) [source]
- NWConnection's waiting state signals lack of connectivity, or a connectivity change during DNS/TCP setup, and is the Network.framework equivalent of waitsForConnectivity; after the connection is up, viability and better-path events report path changes (keep the old connection when viability is lost; open a new one before closing the old on better-path). (medium confidence) [source]
- Apple DTS says both SCNetworkReachability and NWPathMonitor are imperfect (false positives, false negatives, TOCTTOU), so neither should gate user actions; NWPathMonitor is appropriate only when there is no specific network operation to wait for, and the Retry button should not be disabled based on it. (medium confidence) [source]
- SMAppService requires that when a sandboxed app registers a daemon, that daemon is itself sandboxed. Apple DTS called this a deliberate change, enforced in macOS 14.4 and not listed in the release notes. An earlier restriction appeared in macOS 14.2. (medium confidence) (verified as of 2024-03-01) [source]
Measurements and reference values
- One third-party repo reports socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) succeeds inside a sandboxed macOS app (fd 6, errno 0, gateway 3.96 ms), while a raw ICMP socket needs an entitlement. The macOS version and entitlement set were not stated, and it is unconfirmed by Apple. (low confidence) (verified as of 2026-10-02) [source]
Problems, failure modes and limitations
- On macOS, UDP needs the stronger network.server entitlement in addition to network.client even for outgoing-only use, because the system cannot tell UDP is used solely for outgoing 'connections'. Apple DTS stated this in 2017 for a Network Extension provider (an app extension, same rules). (high confidence) [source]
- A child process created by fork, posix_spawn or NSTask always inherits the parent's static sandbox. exec of a different sandboxed executable traps (EXC_BREAKPOINT, SYSCALL_SET_PROFILE) because a process cannot change its sandbox. (high confidence) [source]
- A launchd daemon cannot obtain the location privilege. Apple DTS said 'as things currently stand I don't think it's feasible for a daemon to do this'. A privileged helper or LaunchDaemon cannot read the SSID itself, so the GUI app must read it and pass it over. (medium confidence) [source]
- Notarize from the command line with `xcrun notarytool submit <zip|dmg|pkg> --keychain-profile <name> --wait`, then `xcrun stapler staple` the app, disk image or flat package. A .app cannot be uploaded directly; zip it with `ditto -c -k --keepParent`. altool and Xcode 13 or earlier were refused by the notary service from November 1, 2023. (high confidence) (verified as of 2026-10-02) [source]
- A ZIP can be notarized but not stapled; staple each item inside it, then rezip. Standalone binaries get tickets but cannot be stapled. Without a stapled ticket Gatekeeper must look the ticket up online. (high confidence) [source]
- Always read the notarytool log (`xcrun notarytool log <id> --keychain-profile ...`), even for Accepted submissions; it can carry warnings. A typical failure entry is 'The signature of the binary is invalid.' Notarization is limited to 75 submissions per day. (medium confidence) (verified as of 2026-10-02) [source]
- A VPN that sets includeAllNetworks can still send traffic over the VPN interface even when IP_BOUND_IF names another interface, so an interface-bound monitor probe cannot be assumed to leave via that interface on such hosts. (medium confidence) (verified as of 2024-01-01) [source]
- Local network privacy is supported on macOS from macOS 15; the privilege has three states (Undetermined, Allowed, Denied), the first local network operation triggers the alert, and macOS keeps separate state per user account. MDM cannot configure it. (medium confidence) [source]
- Known macOS defects: very short-lived processes performing a local network operation get no alert (FB16131937, so do not exit immediately after failure); multiple installed copies of an app confuse System Settings (FB15568200); macOS 15.0 had many bugs fixed in 15.1. Community reports describe approved apps still blocked, missing prompts, re-prompts after 15.2/15.4 updates, and NSProcessInfo hostName triggering the prompt. (medium confidence) (verified as of 2026-02-17) [source]
- Apple's Tech Talk 'Adapt to changing network conditions' states that preflight checks with SCNetworkReachability are deprecated in iOS 17.4, and advises: try to connect; use waitsForConnectivity on URLSessionConfiguration or the waiting state on NWConnection so the system retries automatically when conditions change. (medium confidence) (verified as of 2026-10-02) [source]
- A Mac App Store app cannot bundle an unsandboxed privileged helper: Apple DTS states all code shipped via the MAS must be sandboxed, and SMJobBless was never usable from a sandboxed app. DTS advises shipping the privileged daemon as a separate product (installer package or separate app that uses SMAppService), downloaded outside the MAS. (high confidence) [source]
- SMAppService.agent installs a per-user LaunchAgent only (current user, ~/Library/LaunchAgents); the API cannot install an agent for all users (Apple DTS). (medium confidence) [source]
- A helper-app login item (SMAppService.loginItem(identifier:)) must be bundled at MyApp.app/Contents/Library/LoginItems/Helper.app. The older SMLoginItemSetEnabled is deprecated from macOS 13. Status 78 (EX_CONFIG) means launchd rejected the job plist; a stale Launch Services database from many dev builds is a common cause. (medium confidence) [source]
Comparisons and alternatives
- IP_BOUND_IF (IPPROTO_IP) and IPV6_BOUND_IF (IPPROTO_IPV6) take an interface index from if_nametoindex() and limit transmission and reception to that interface; Apple's recommendation is to use them rather than bind() to an interface's IP address. (high confidence) [source]
- An Apple DTS test on macOS 13.5 showed IP_BOUND_IF forcing a connection through a VPN utun interface versus the default en0 route; DTS said it has worked this way for decades. (medium confidence) [source]
- SMAppService.Status has four values: notRegistered, enabled, requiresApproval, notFound. A user can disable the item in System Settings > Login Items, which leaves it disallowed in the background-task database. The app should read status and prompt rather than assume success. (medium confidence) [source]
Facts and statements
- In App Sandbox, com.apple.security.network.client covers outgoing connections and com.apple.security.network.server covers listening sockets for incoming connections; both directions can send and receive data, the difference being who initiates. (high confidence) [source]
- Apple DTS (2016): ICMP, like UDP, requires both network.client and network.server; with both, sending and receiving pings works. Without them sendto fails with EPERM and the sandbox logs 'deny network-outbound'. (high confidence) [source]
- A developer reported in Oct 2024 that UDP broadcast sendto in a sandboxed app required both entitlements, and that App Review accepted the app with network.server declared. (low confidence) (verified as of 2024-10-01) [source]
- The network entitlements only apply if App Sandbox is enabled; Hardened Runtime adds no networking checks (Apple DTS, March 2025). A Developer ID twin build that is not sandboxed needs neither entitlement. (medium confidence) (verified as of 2025-03-01) [source]
- An embedded helper executable you spawn must be signed with exactly com.apple.security.app-sandbox and com.apple.security.inherit; any other sandbox entitlement aborts the child. The child inherits only the parent's static entitlements, not rights granted after launch (e.g. PowerBox). Apple recommends XPC services over child processes. (high confidence) [source]
- Spawning system tools such as /sbin/ping from a sandboxed app is constrained by the inherited sandbox, so the parent must hold network.client and network.server for ICMP to work; this is inference from the inheritance and ICMP rules, not a documented ping-specific statement. (low confidence) [source]
- Since macOS Sonoma (change landed in Sonoma beta 2), CWInterface.ssid() requires the location privilege. Apple DTS relayed from the CoreWLAN team that this was deliberate, and the CWInterface.h comment reads: 'SSID information is not available unless Location Services is enabled and the user has authorized the calling app to use location services.' Without it, ssid() returns nil. (high confidence) [source]
- A sandboxed app needs the App Sandbox entitlement com.apple.security.personal-information.location (Xcode: Signing & Capabilities > App Sandbox > App Data > Location) to be eligible for Core Location authorization, plus com.apple.security.network.client. Forum users report this working. A DTS engineer said no restricted entitlements or provisioning profile are needed for CoreWLAN itself. (medium confidence) [source]
- For a LaunchAgent registered via SMAppService.agent(plistName:), request Location authorization from the container GUI app, not the agent. TCC treats the app as the agent's responsible code, so the grant should extend to the agent. A reporter on macOS 26.3 saw the agent get nil while the app did not, and DTS advised this approach. (medium confidence) (verified as of 2026-02-01) [source]
- Shell-level SSID routes were closed in macOS 14.x: the airport tool stopped returning connection info in 14.4, and wdutil info shows 'redacted' for MAC address, SSID and BSSID from 14.5. networksetup -getairportnetwork still worked per admins, with no guarantee. These routes are unavailable to a sandboxed App Store app anyway. (low confidence) (verified as of 2024-05-01) [source]
- Apple's notary service requires: valid code signatures on all executables, a Developer ID (not Mac Distribution/ad hoc/development) certificate, the Hardened Runtime on app and command-line targets, a secure timestamp, no com.apple.security.get-task-allow set to true, and linking against the macOS 10.9 or later SDK. (high confidence) [source]
- Hardened Runtime and App Sandbox are independent technologies. The sandbox is mandatory for the Mac App Store; the Hardened Runtime is required for Developer ID notarization while the sandbox is optional there. A Developer ID twin can therefore be hardened with or without the sandbox. (medium confidence) [source]
- macOS Sequoia (15) removed the Control-click > Open override for software that is not correctly signed or notarized. Users must go to System Settings > Privacy & Security and click Open Anyway, which makes an unnotarized Developer ID twin much harder to install. A properly notarized build avoids that path. (high confidence) (verified as of 2024-08-07) [source]
- Notarized apps have been reported as wrongly flagged 'damaged' by Gatekeeper, and the Control-click bypass never fixed that case. This scopes the headline: notarization is necessary for a clean first launch but not always sufficient. (low confidence) (verified as of 2024-07-05) [source]
- Plug-ins and frameworks loaded by a hardened host inherit the host's entitlements; a host that loads third-party code may need com.apple.security.cs.disable-library-validation. A network-monitor twin that loads no plug-ins normally needs none of the cs.* runtime exceptions. (low confidence) [source]
- Do not hard-code BSD interface names such as pdp_ip0 or assume IPv4 is present; resolve the interface at runtime and use IPV6_BOUND_IF where only IPv6 exists. For TCP/UDP, Apple DTS prefers Network.framework requiredInterfaceType. (medium confidence) [source]
- NWParameters exposes requiredInterface, requiredInterfaceType, prohibitedInterfaces and prohibitedInterfaceTypes under 'Selecting Paths' for connections and listeners (and browsers for requiredInterface); this is the Network.framework counterpart of interface-bound sockets. Exact availability strings were not retrieved. (low confidence) [source]
- Sandbox behaviour: sources show only that network operations are denied without the network entitlements (sandbox log 'deny(1) network-bind*:0' on iOS, where App Sandbox entitlements do not apply). No source states that the IP_BOUND_IF setsockopt itself is sandbox-restricted or exempt; assume it is governed by the network.client/server entitlement on connect/bind and verify empirically. (low confidence) [source]
- IP_RECVIF only filters received packets and does not direct outbound traffic; for outbound or broadcast traffic on macOS use IP_BOUND_IF (DHCP library issue, 2020). (low confidence) [source]
- Outgoing TCP connect, UDP unicast/multicast/broadcast send, connecting a UDP socket, and receiving UDP multicast/broadcast need local network access. Listening for/accepting TCP and receiving UDP unicast do not. The check sits deep in the stack, so it applies to Network.framework, BSD sockets and URLSession alike. (low confidence) [source]
- Exemptions: traffic to a DNS server or network proxy that sits on the local network does not need access, nor does resolving a non-local DNS name with the system resolver. Resolving a .local name does need access. A network/DNS monitor that probes arbitrary LAN hosts or uses mDNS is therefore affected, but plain queries to the configured resolver are not. (low confidence) [source]
- All Bonjour operations (register, browse, resolve) require local network access, across DNS-SD, Network.framework and Multipeer Connectivity. NSBonjourServices lists the service types the app uses (format _type._tcp / _udp); NSLocalNetworkUsageDescription supplies the alert text for any direct or indirect local network use. Both go in the app's Info.plist (the container app, not extensions). (medium confidence) [source]
- If the user later grants access, NWConnection retries automatically; if the user revokes access, an established TCP connection to a local address is closed and new ones go to .waiting. The system may deny an operation immediately while the alert is still showing, so use waiting-for-connectivity APIs (Network.framework, URLSession waitsForConnectivity) or retry logic. (low confidence) [source]
- Identity is tracked by code signature and main-executable UUID: sign with an Apple-issued identity (not ad hoc) and keep a unique UUID, otherwise behavior can be erratic. The multicast entitlement is not required on macOS. (low confidence) [source]
- macOS 15.5 added two sudo-set defaults in domain com.apple.network.local-network, AllowedEthernetLocalNetworkAddresses and AllowedWiFiLocalNetworkAddresses (arrays of CIDR strings) that exempt whole networks from the privilege; a restart is needed. An Apple DTS engineer recommended them for unattended CI in April 2026. (medium confidence) (verified as of 2026-04-01) [source]
- Do not hard-code en0 as the Wi-Fi interface; apps that do can appear to bypass or break the alert. Run discovery on all broadcast-capable interfaces, or filter getifaddrs by the SIOCGIFFUNCTIONALTYPE ioctl. (low confidence) [source]
- SCNetworkReachabilityGetFlags is synchronous yet can block the calling thread while name resolution completes, whereas NWPathMonitor is asynchronous and delivers its first status via callback, so callers must tolerate a delayed initial update. (low confidence) [source]
- Reading NWPathMonitor.currentPath right after creating the monitor returns .unsatisfied; Apple DTS says to set pathUpdateHandler and call start(queue:) first. The handler runs on the supplied queue, so UI work must hop to main. (low confidence) [source]
- NWPathMonitor interface reporting is coarse for a monitoring tool: a 2022 forum report describes availableInterfaces/isExpensive staying on the cellular interface after joining Wi-Fi (iOS, captive-style school Wi-Fi, unanswered), and secondary reports say VPN tunnels classify as NWInterface.InterfaceType.other and availableInterfaces order is not a documented route-preference signal. (low confidence) (verified as of 2022-01-01) [source]
- For interface type checks on a path, Apple DTS prefers repeated nw_path_uses_interface_type() calls over enumerating interfaces with nw_path_enumerate_interfaces(). (low confidence) [source]
- Under the same restriction, sandboxed daemons on macOS 14.4 may not set StandardInputPath, StandardOutputPath or StandardErrorPath in their launchd plist; registration fails if they do. (low confidence) (verified as of 2024-03-01) [source]
- App Review Guideline 2.4.5 forbids MAS apps from requesting escalation to root or using setuid (v), from auto-launching or running code at startup or login without consent (iii), and from downloading or installing additional code or standalone apps (iv). Login items need an explicit user opt-in; root helpers are rejected. (medium confidence) (verified as of 2026-10-02) [source]
- SMAppService daemons and agents live inside the app bundle: the daemon plist at Contents/Library/LaunchDaemons/<id>.plist, with the executable referenced by a bundle-relative path. Registering a daemon requires user approval in System Settings, then admin authentication. After approval, re-registering needs no further authentication. (medium confidence) [source]
- SMAppService.mainApp (macOS 13+) registers the app itself as a login item with no helper bundle. Secondary sources describe it as sandbox and App Store compatible. Not checked against Apple's reference page. (low confidence) [source]
- Developer ID twin build: a non-sandboxed build can bundle a privileged daemon, register it with SMAppService.daemon (macOS 13+), and run it as root after user approval. The MAS build should omit this and use only mainApp or loginItem. The two builds need separate entitlements and targets. (medium confidence) [source]
Children
- AllowedWiFiLocalNetworkAddresses CI configuration (frontier)
- App Sandbox network entitlements client and server semantics UDP ICMP and child-process inheritance
- Background Task Management and System Settings Login Items approval (frontier)
- CWWiFiClient event monitoring without Location (frontier)
- CoreWLAN SSID access and Location Services authorization
- Embedding a helper tool in a sandboxed app (frontier)
- Hardened Runtime Gatekeeper and notarization for a Developer ID twin build
- Interface-bound sockets IP_BOUND_IF and required_interface and sandbox behaviour
- Local Network privacy TN3179 NSBonjourServices and detecting a denial
- Location usage-string wording for App Review (frontier)
- NECP and includeAllNetworks routing precedence (frontier)
- NWBrowser waiting-state handling for -65570 (frontier)
- NWConnection waiting state and viability handlers (frontier)
- NWParameters requiredInterface vs prohibitedInterfaceTypes (frontier)
- NWPathMonitor requiredInterfaceType and prohibitedInterfaceTypes (frontier)
- Network.framework NWPathMonitor and NWConnection versus SCNetworkReachability
- Notarized Developer ID daemon registration (frontier)
- Notarytool CI automation (frontier)
- Provisioning profiles for Developer ID sandboxed builds (frontier)
- SCDynamicStore for DNS and interface change notifications (frontier)
- SMAppService login items and privileged helpers for Mac App Store versus Developer ID
- Sparkle or auto-update signing for the twin (frontier)
- TCC responsible-code inheritance for SMAppService agents (frontier)
- XPC from sandboxed app to loginItem helper (frontier)
- XPC service privilege separation (frontier)
- launchd agent AssociatedBundleIdentifiers for helper attribution (frontier)
Frontier under this node: AllowedWiFiLocalNetworkAddresses CI configuration, Background Task Management and System Settings Login Items approval, CWWiFiClient event monitoring without Location, Embedding a helper tool in a sandboxed app, Location usage-string wording for App Review, NECP and includeAllNetworks routing precedence, NWBrowser waiting-state handling for -65570, NWConnection waiting state and viability handlers, NWParameters requiredInterface vs prohibitedInterfaceTypes, NWPathMonitor requiredInterfaceType and prohibitedInterfaceTypes, Notarized Developer ID daemon registration, Notarytool CI automation, Provisioning profiles for Developer ID sandboxed builds, SCDynamicStore for DNS and interface change notifications, Sparkle or auto-update signing for the twin, TCC responsible-code inheritance for SMAppService agents, XPC from sandboxed app to loginItem helper, XPC service privilege separation, launchd agent AssociatedBundleIdentifiers for helper attribution