Network Extension

RSS for tag

Customize and extend the core networking features of iOS, iPad OS, and macOS using Network Extension.

Posts under Network Extension tag

200 Posts

Post

Replies

Boosts

Views

Activity

Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post URL filter: WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension URL filters documentation Filtering traffic by URL sample code Setting up a PIR server for URL filtering sample code Using the Bloom filter tool to configure a URL filter sample code PIR Service Example open source server sample and specifically its documentation Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
4.3k
Aug ’26
URL Filter (Oblivious HTTP) configuration In Review for almost a week with no feedback
Hello, I submitted a Network Extension URL Filter (Oblivious HTTP) configuration in CloudKit Console almost a week ago. It still says In Review / Waiting for Approval and I haven't heard anything back since the submission notice. I wanted to check whether anything is missing on my end. Just in case, the configuration ID is 60802ed4-abfa-4b20-a64e-0d35230f478a. The app is an open-source ad and tracker blocker from the developers of an existing content blocker with a large user base. On iPhone and iPad its system-wide blocking runs entirely through the URL filter. Until the configuration is approved the iOS app can't block anything at all, and our testers are left with a Mac-only product in the meantime. Because lookups go through Apple's relay to our own PIR server, we never learn which sites anyone visits. All four endpoints have been live since the day I submitted and the TXT records are in place. Every database we build also includes the www.apple.com/url-filter-test validation entry. Is there anything else I need to provide, or a rough timeline I should expect? Thank you in advance!
0
0
23
26m
[macOS 27.2]: System-Wide DNS Resolution Failures After Sleep/Wake – mDNSResponder and NETransparentProxyProvider
Summary Recent macOS release observed intermittent system-wide DNS failures after sleep/wake on multiple devices running Global Secure Access (GSA) with NETransparentProxyProvider. Previously successful DNS lookups time out after wake across applications, including browsers and GSA. Two captures contain failure-time evidence of the mDNSResponder resolver queue predominantly waiting in close()/kernel. Other captures show similar DNS failures, but a shared root cause has not been established. Call chain, from thread entry to kernel wait: start_wqthread + 8 _pthread_wqthread + 292 _dispatch_workloop_worker_thread + 720 _dispatch_root_queue_drain_deferred_wlh + 284 _dispatch_lane_invoke + 392 _dispatch_lane_serial_drain + 332 _dispatch_source_invoke + 920 _dispatch_source_cancel_callout + 208 _dispatch_continuation_pop + 596 _dispatch_client_callout + 16 close + 8 fleh_synchronous + 72 sleh_synchronous (sleh.c:1610) unix_syscall (systemcalls.c:181) fp_close_and_unlock_with_action (kern_descrip.c:1874) fg_drop (kern_descrip.c:287) soclose (uipc_socket.c:1345) soclose_locked (uipc_socket.c:1138) cfil_sock_close_wait (content_filter.c:5743) soflow_db_apply (socket_flows.c; line unavailable) cfil_filters_udp_attached_per_flow (content_filter.c:6675) _sleep (kern_synch.c:213) lck_mtx_sleep_deadline (locks.c:1583) thread_block_reason (sched_prim.c:4060) thread_invoke (sched_prim.c:3443) Steps to reproduce The issue is intermittent. These steps describe the observed sequence, not a deterministic minimal reproduction. Run the GSA client using NETransparentProxyProvider. The affected configurations also have Microsoft Defender network extensions active. Verify that a system DNS lookup succeeds for a known hostname. Allow the Mac to sleep, including maintenance DarkWake cycles. Wake the Mac and repeat system DNS lookups or use applications requiring hostname resolution. Observe repeated approximately 30-second lookup timeouts, sometimes longer. Observed results November 5, 2026 - UTC+05:30 capture User-reported impact: Recurrence of the same sleep/wake connectivity symptoms. OS: macOS 27.2 (26B123). Incident window: 20:38-20:41 IST / 15:08-15:11 UTC. The same Chrome client/name A lookup succeeds earlier in 12.984 ms but times out after wake in 29,999.705 ms. The DNS service/server route changed, so this is not a controlled identical-network comparison. The resolver records 1,007 timeout callbacks during the incident window, across browsers, Teams, GSA, Defender and other processes. The failure-time spindump at 20:40:21.009-20:40:31.013 IST shows the original mDNSResponder PID 78534 with 715/715 resolver-queue samples under dispatch-source cancellation → close() → kernel → lck_mtx_sleep_deadline. Source: spindump.txt:75998-76093. This establishes a sampled wait, not a permanent deadlock or proof of the same root cause as November 2. The file descriptor and kernel/filter wait owner remain unidentified. A later matching Chrome lookup returns an address at 20:43:18.191816 IST on the same resolver PID, without a recorded resolver restart. This establishes some recovery, not that every application or tunnel recovered. November 2, 2026 - UTC-08:00 capture User-reported impact: No network upon wake. This eventually resolves without a reboot, after approximately 5 to 15 minutes of waiting. OS: macOS 27.2 (26B123). Incident window: 09:40-09:45 PST / 17:40-17:45 UTC. The same Edge A lookup succeeds before sleep in 19.346 ms but times out after wake in 29,999.826 ms. The resolver records 1,403 timeout callbacks during the incident window. The failure-time spindump shows 770/777 resolver-queue samples under dispatch-source cancellation → close() → kernel; 769 include lck_mtx_sleep_deadline. This establishes a dominant sampled wait, not a permanent deadlock. The file descriptor and kernel/filter wait owner remain unidentified. November 3, 2026 - UTC-08:00 capture (Mihai) Evidence: mihai_gsa_error.tar.gz The following example records a failure resolving GSA’s own control-plane endpoint, whose DNS lookup is not intercepted by the GSA tunnel. Times in these excerpts are local (UTC-08:00). GSA error [2026-11-03 10:13:58.463] Network connection to the Global Secure Access Edge could not be established StreamId: ControlStream Hostname: <tenant>.auth.client.globalsecureaccess.microsoft.com:443 Error: hostname lookup error: Address lookup failed os_error: nodename nor servname provided, or not known syscall: getaddrinfo mDNSResponder records 10:13:19.663661 [R125367->DupQ50990->Q38408] Duplicate question <private> dn:04wpeA (Addr) 10:13:58.468519 [R125367] DNSServiceQueryRecord STOP -- name hash: dn:04wpeA, duration: 39s 10:13:59.078847 [R125340] QueryRecordOpCallback: Question <private> dn:04wpeA (Addr) timing out, InterfaceID 0x0 Additional observations The original resolver records 11 timeout callbacks across GSA, Defender, Spotify and the system time service. A GSA A-query returns a positive result in 1.282 ms earlier (cache-compatible, not a cold upstream baseline), then the same client/name/qtype/flags times out after 41.865784 wall-clock seconds; that interval includes sleep. The DNS service/server set changes, so this is not a controlled same-network comparison. At 09:40 PST the Wi-Fi interface becomes inactive and loses its IPv4 address, followed by no-dns-service results. The first native lookup errors precede this link loss; it does not explain the entire case. Four GSA A/AAAA timeout transactions have matching late UDP replies. For one A-query, the reply is logged 25.095999 seconds after its matching send and 7.197434 seconds after the API timeout, during shutdown. 48 acceptable UDP response records appear within 1.467 ms. The location of the delay is not identified.
5
1
299
49m
Is it safe to strip with All Symbols for a content filter?
We would like to minimise the amount of code exposed in the product we have developed and an obvious option is to configure our build setting to use the All Symbols for Strip Style. Some investigation with an AI tool reports there are possible problems doing so. ContentFilter: non-global → all — risky. The NetworkExtension and XPC subsystems load your bundle and look up classes by name through the ObjC runtime, which uses __objc_classlist and friends (not the Mach-O symbol table), so in principle all works. In practice it occasionally breaks bundle loading in edge cases. If you try this, test specifically that systemextensionsctl activates the bundle and the filter actually traps packets. Is it safe to use All Symbols with a content filter or do we need to accept Non-Global symbols? Thanks, Dave
1
0
124
4h
NETransparentProxyManager: saving isOnDemandEnabled = true disables On-Demand on other proxies
On macOS, multiple NETransparentProxyManager (NEAppProxyProvider) configurations from different vendors can be enabled (isEnabled = true) and run simultaneously. However, we discovered that when one NETransparentProxyManager configuration calls saveToPreferencesWithCompletionHandler: with isOnDemandEnabled = true, /usr/libexec/nehelper (NEConfigurationManager) silently modifies any other enabled NETransparentProxyManager configuration in /Library/Preferences/com.apple.networkextension.plist and flips its OnDemandEnabled to false (and nesessionmanager logs Resetting VPN On Demand and marks the other session not-kernel-activated). Unlike NEVPNManager.isEnabled (which documents mutual exclusion for personal VPNs), NETransparentProxyManager is designed so multiple transparent proxies can coexist simultaneously, and neither NETransparentProxyManager.h nor NEVPNManager.h documents that isOnDemandEnabled is mutually exclusive across coexisting transparent proxy configurations. Root Cause Observed in NetworkExtension.framework When inspecting -[NEConfigurationManager saveConfigurationToDisk:updateSCPreferences:currentSignature:userUUID:notifyNow:isUpgrade:], when iterating over existing NEConfiguration objects of the same grade: If [[newConfig VPN] isEnabled] && [[otherConfig VPN] isEnabled] && [[newConfig VPN] isOnDemandEnabled] && [[otherConfig VPN] isOnDemandEnabled], NEConfigurationManager invokes: +[NEConfigurationManager disableConfiguration:otherConfig onDemandOnly:YES] disableConfiguration:onDemandOnly:YES calls [[otherConfig VPN] setOnDemandEnabled:NO], even when both configurations are NETransparentProxyManager (TunnelType == 2). Real-World Impact When two enterprise security products that both use NETransparentProxyManager are installed on the same Mac: Both configure isEnabled = true, onDemandRules = [NEOnDemandRuleConnect()], and isOnDemandEnabled = true. Whenever Proxy A saves its preferences, nehelper silently flips Proxy B's isOnDemandEnabled to false (and vice versa). After a reboot or network transition where Proxy B's initial startVPNTunnel fails while Wi-Fi is still associating and Proxy B relies on VPN On Demand (NEOnDemandRuleConnect) to start its NEAppProxyProvider once network connectivity comes up, macOS never starts Proxy B because its isOnDemandEnabled flag was cleared. Minimal Reproducer (Swift) Compile this minimal CLI inside an app bundle signed with the com.apple.developer.networking.networkextension = ["app-proxy-provider"] entitlement: import Foundation import NetworkExtension let args = CommandLine.arguments let name = args.count > 1 ? args[1] : "PocProxyA" let action = args.count > 2 ? args[2] : "status" DispatchQueue.main.async { NETransparentProxyManager.loadAllFromPreferences { managers, error in if let error = error { print("[\(name)] loadAllFromPreferences error: \(error)") exit(1) } let all = managers ?? [] let existing = all.first(where: { $0.localizedDescription == name }) if action == "status" { if let mgr = existing { print("[\(name)] -> isEnabled=\(mgr.isEnabled), isOnDemandEnabled=\(mgr.isOnDemandEnabled), rulesCount=\(mgr.onDemandRules?.count ?? 0)") } else { print("[\(name)] -> not found") } exit(0) } if action == "remove" { guard let mgr = existing else { exit(0) } mgr.removeFromPreferences { err in print("[\(name)] removed (err=\(String(describing: err)))") exit(0) } return } // action == "save" let mgr = existing ?? NETransparentProxyManager() let proto = (mgr.protocolConfiguration as? NETunnelProviderProtocol) ?? NETunnelProviderProtocol() proto.providerBundleIdentifier = "com.example.poc.extension" proto.serverAddress = "127.0.0.1" mgr.protocolConfiguration = proto mgr.localizedDescription = name mgr.isEnabled = true mgr.onDemandRules = [NEOnDemandRuleConnect()] mgr.isOnDemandEnabled = true print("[\(name)] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true...") mgr.saveToPreferences { err in if let err = err { print("[\(name)] saveToPreferences error: \(err)") exit(1) } print("[\(name)] saveToPreferences succeeded! isEnabled=\(mgr.isEnabled), isOnDemandEnabled=\(mgr.isOnDemandEnabled)") exit(0) } } } RunLoop.main.run()Reproduction Output Running save on PocProxyA, then save on PocProxyB, and checking status on both: === Step 1: PocProxyA saves isOnDemandEnabled = true === [PocProxyA] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyA] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true [PocProxyA] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 === Step 2: PocProxyB saves isOnDemandEnabled = true === [PocProxyB] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyB] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true === Step 3: Check BOTH configurations after PocProxyB saved === [PocProxyA] -> isEnabled=true, isOnDemandEnabled=false, rulesCount=1 [PocProxyB] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 === Step 4: PocProxyA saves isOnDemandEnabled = true again === [PocProxyA] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyA] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true === Step 5: Check BOTH configurations after PocProxyA saved === [PocProxyA] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 [PocProxyB] -> isEnabled=true, isOnDemandEnabled=false, rulesCount=1Questions Is disableConfiguration:onDemandOnly:YES stripping isOnDemandEnabled across coexisting NETransparentProxyManager (TunnelType = 2) configurations a bug in NEConfigurationManager, or an intentional limitation? Is there a recommended way for two coexisting NETransparentProxyManager configurations from different vendors to both use On-Demand without disabling each other's isOnDemandEnabled flag on saveToPreferences? Filed in Feedback Assistant as FB25463155.
3
2
286
1d
NEAppPushProvider times out connecting to a server on a routed subnet, while the containing app connects fine
We use Local Push Connectivity (NEAppPushProvider, matchSSIDs set) to receive notifications from an on-premise MQTT broker over WebSocket (wss://host:port/mqtt). iPhone on Wi-Fi, VLAN A (SSID matches matchSSIDs) Server on wired VLAN B, routing and firewall rules allow VLAN A → VLAN B on that port Result: the containing app, in the foreground, connects successfully to wss://<VLAN B IP>:<port>/mqtt. At the same moment, the app push provider (URLSessionWebSocketTask to the exact same URL) fails with "The request timed out". The provider starts normally (start() is called). When the server has an address on the Wi-Fi subnet (VLAN A), the provider connects without any issue. Is the app push provider restricted to servers on the local subnet of the matched Wi-Fi network? If so, is this documented anywhere? If not, what could prevent the provider from reaching a routed address that the app itself can reach? iOS version: 27.0.1 device : iPhone 13
1
0
78
1d
NEURLFilterManager: inconsistent per-domain blocking (some sites never block, one flaps) - confirmed PIR database is correct
Hello, Some context: DropBet is an app that helps people with gambling addiction stay off gambling sites and apps, using NEURLFilterManager/PIR to block a large list of known gambling domains system-wide. For a lot of our users this filter is a core part of their recovery > reliability really matters here. Since fixing an unrelated HPKE encryption bug (separate thread, now closed), the filter works end-to-end for the first time, but blocking is inconsistent per domain in a way I can't explain from my side: winamax.fr and the Winamax app: blocked reliably, every single time > clean "connection failed" style block, confirmed to load fine with protection off. unibet.fr and betclic.fr: never blocked, consistently > confirmed even after a full device reboot (rules out stale caching), and confirmed identical across both Safari and Chrome on iOS tested side-by-side (so not browser-specific). olybet.fr: flaps > the page reloads every 2-3 seconds with protection on, also identical across both browsers. Confirmed this only happens with the filter enabled (tested toggling protection off/on against the same page). unibet.fr auto-redirects into the native Unibet app via a Universal Link before the page loads, unlike betclic.fr which stays in the browser > different code path, possibly relevant. To rule out any issue on our end, I wrote a standalone test that queries our deployed PIR database shards directly - bypassing OHTTP, the app, and the device entirely - for all of the domains above plus their www. variants. All of them correctly return the blocked value, no exceptions, including unibet.fr and betclic.fr which never block on the actual device. So the database, the PIR protocol implementation, and the server are confirmed correct for every domain I've tested. This points at something in how NEURLFilterManager/ciphermld applies a correctly-received PIR verdict on-device - possibly related to query batching, an evaluation-key edge case, or Universal Link handling bypassing the filter before a web request is even made. Is there anything you can share about how the client applies results once decrypted, or known issues around any of this?
5
0
126
1d
NEURLFilter configuration still "Queued" six weeks after submission
Our Network Extension URL Filter configurations in CloudKit Identity & Trust are not moving through onboarding. STG: configuration 6e17673d-dbaa-4b35-98c5-ff9e7a357577, bundle ca.itellyou.stg. Submitted 2026-09-25, status Approved, Onboarding Status "Queued". PRD: configuration 06fa2558-281b-4b55-b59f-402ecf359d18, bundle ca.itellyou. Submitted 2026-10-20, status In Review. Evidence (iPhone 17 Pro Max, 2026-11-06, same commit, same server, same user token): Development-signed build: the filter reaches "running" and blocks our test domains. Ad-hoc (distribution-signed) build: it cycles starting -> stopped with NEURLFilterManager.Error 9. The PIR server, Privacy Pass issuer and OHTTP gateway are live, and the test entry www.apple.com/url-filter-test is present. An Apple engineer confirmed on GitHub (apple/pir-service-example#185) that nothing is pending on our side. We also opened support case 30000007408474. Has anyone seen how long onboarding takes these days, or found a way to get it moving?
1
0
80
2d
Egress addresses of the URL filter OHTTP relay
Hello, I am wondering about the egress addresses of the Oblivious HTTP relay that Apple runs for Network Extension URL filters. I am building an iOS app that uses NEURLFilterManager. The app builds a Bloom filter from the block lists a user picks. The system only asks our server about a site when that filter has a hit. Each lookup is encrypted with keyword PIR and carries a Privacy Pass token instead of anything tied to the user. It reaches our server through your relay, which strips the device's address. We run our own PIR server, Privacy Pass issuer and OHTTP gateway instead of a hosted service. The gateway is the one part of the setup that should only ever hear from your relay. Since every real lookup comes through the relay, I would really like to drop all other traffic to it at the firewall. Right now I can't do that. I also can't rate limit by address because every legitimate request shares the relay's addresses. As a result the gateway just has to stay open to everyone and rely on global limits, which is a far cry from what I'd want for a service that only one client is meant to reach. I have three questions about this. 1) Are the relay's egress address ranges published somewhere, or can they be shared with developers who have been onboarded? 2) If they are shared, how would we find out when they change and how much notice there is? 3) If the addresses can't be shared, is there another way to tell that a request came from the relay, such as a header or a client certificate? Please let me know if any of this is unclear or if there is a better place to ask. Thank you in advance, Alexander
0
0
62
2d
Apple thought it was impossible
Apple thought it was impossible. I made it possible. No server. Just an iPhone. LUMEN-JEV OS v3.0 — On-device OS using Pyto + iCloud Drive + Obsidian Architecture: Pyto runtime = server: Persistent loop, 922 tickers scanned, 502.6 ev/s, 12ms latency, sub-2ms cache iCloud Drive = bus: Writes JEV-BUS.md every 15s, shared working directory Obsidian = OS window manager: 00-JEV-DASHBOARD-main 48 nodes live Vault: 11/11 LOCKED, Factory Complete Anchor: 572b9df5e8e1f101365f8316ba7b34da4aa54ff89a2dcdb68ed20b126e8cabed Chain: REAL-EXCHANGE-PUBLIC-WS -> 8-MODULE-DEMO -> DEMO-TERMINATED -> NO EXECUTION Feed: real-public-readonly / public_ticker_only Modules (8-MODULE-v1px): WARREN-WATCHDOG, KEEPER-BOX, NODE-MODE-SYNC, VAULT-MULT, SCOUT-SCAN, SIREN-FILTER, FOCUS-SIGNAL-20K, ORACLE-PRICE-FEED, RELAY-ROUTER, AKE-ARBITRAGE, YIELD-BACK-4, MEDUSAs: 03 DYNAMIC OBSERVER-SPACE Context: Built in 33hrs over 11 nights, day job, single dad, solo dev, on iPhone only. Pyto working directory set to iCloud Drive. No Mac backend, no CloudKit function, no external server. Why this matters for iOS: Apple's sandbox says you can't run a persistent OS-like loop with live file sync on iOS. Pyto + iCloud Drive persistence proves you can. iPhone becomes the server. Proof: 48 NODES LIVE canvas PROOF CHAIN 11/11 FLAT VIEW VAULT LOCKED Jev.py V2.6 CLEAN BUS log (checked 50/100/150/200 -> 922/922 passes) Anchor hash matches zip JEV-OS-v3.0-572b9df5-40files.zip Requesting: Guidance on showcasing this as an iOS innovation + Ask Apple office hours. X proof pinned: @Activepython007
22
1
1.3k
4d
Is a `flowClosed` report guaranteed when the owning process exits or crashes?
Our macOS NEFilterDataProvider sets shouldReport = true on flow verdicts and receives NEFilterReport.Event.flowClosed in handle(_:). In testing, we have observed close reports after the owning process exits or crashes, sometimes with a short delay. Is a flowClosed report guaranteed for every TCP and UDP flow in these cases? Does the behavior differ by protocol, and is there a documented upper bound on delivery time? We also set statisticsReportFrequency = .low. Does that setting affect only periodic .statistics reports, with no effect on flowClosed delivery?
2
0
109
5d
NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hello ! following up from a related thread (account transfer issue, now resolved: https://developer.apple.com/forums/thread/843546?answerId=911820022), but this is a distinct, new issue so starting fresh as suggested. The extension launches fine, XPC handshake succeeds, and PIR registration completes successfully. But the subsequent NEPIRChecker status check fails every time (retried repeatedly over several minutes, same result each time): PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x677037cf0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}>Config being registered (confirmed from the logs): pirServerURL = https://pir.dropbet.app/ pirPrivacyPassIssuerURL = https://pir.dropbet.app/issueBoth endpoints are live and were already validated as part of the original NEURL Filter configuration approval. I've captured a sysdiagnose from the device right when this was happening, so I have that ready to attach to a bug report if useful — just let me know and I'll file one. Any idea what CipherML error 1100/1800 typically indicates?
8
0
487
6d
Cannot open Chrome UDP flows in Transparent Proxy Provider
We are implementing a Transparent Proxy for HTTPS (via TCP and QUIC). The following rules are set in startProxy: settings.includedNetworkRules = [ NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "443"), prefix: 0, protocol: .TCP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "::", port: "443"), prefix: 0, protocol: .TCP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "443"), prefix: 0, protocol: .UDP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "::", port: "443"), prefix: 0, protocol: .UDP) ] Handling TCP connections seems to work fine. But opening UDP flows from Chrome (or Brave) always fails with Error Domain=NEAppProxyFlowErrorDomain Code=2 "The peer closed the flow" (Doing the same for Firefox works!) BTW: We first create a remote UDP connection (using the Network framework) and when it is in the ready state, we use connection?.currentPath?.localEndpoint as the localEndpoint parameter in the open method of the flow. Is it a known issue that QUIC connections from Chrome cannot be handled by a Transparent Proxy Provider?
11
0
1.6k
1w
iPadOS: Intermittent disconnection after NEHotspotConfigurationManager automatic hotspot join
Background We are developing Share&Share, an offline device-to-device content transfer application. An iPad automatically joins a nearby Samsung Android LocalOnlyHotspot. The hotspot credentials are delivered through an authenticated, encrypted Bluetooth Low Energy (BLE) session. On iPadOS, our application decrypts the credentials natively in Swift and uses NEHotspotConfigurationManager.apply() to join the hotspot. We are investigating an intermittent connection problem during the initial automatic join. We have also submitted a private report through Apple Feedback Assistant: Feedback ID: FB25408475 Test environment Receiver: Physical iPad with a Home button. Sender/hotspot: Samsung SM-E055F. Android version: Android 16. Hotspot security: WPA2/WPA3 transition configuration. iOS implementation: Swift and NetworkExtension. joinOnce = false. The hidden property is not explicitly set. Observed behaviour Two independently instrumented automatic-join sessions showed a similar sequence: A1: The iPad associates with the Samsung hotspot and completes the WPA3 authentication exchange recorded by the Samsung. Approximately 3.35 seconds after the iPad-side join completion, iOS records a beacon-loss/roam declaration and the connection drops. A2: iOS attempts to reconnect, but the authentication exchange does not complete. A3: iOS automatically reconnects successfully, obtains a DHCP address and remains connected during the observation period. The same encrypted credentials work during both the initial and subsequent successful attempts. The apply() completion handler returns without an error. We understand that this does not establish that the device has joined successfully or that local IP connectivity is ready. What we have investigated The first join used cached beacon information approximately eight seconds old; the subsequent successful join used fresh scan information. AWDL activity was observed, but we have not established a causal relationship. Location Services scanning does not explain the first failure in our second instrumented session. The diagnostic label "Beacons Lost" is not being treated as proof of actual missed beacon frames. We have not independently established which WPA mode the iPad negotiated. We have not yet measured TCP readiness during the failed and successful attempts. We do not currently have a standalone minimal Xcode reproduction project. The behaviour was observed using our Flutter-based iOS probe and physical devices. Questions for developers familiar with NetworkExtension Has anyone observed intermittent first-join instability with NEHotspotConfigurationManager when joining a newly created Android LocalOnlyHotspot using WPA2/WPA3 transition mode? Are there documented limitations or known issues involving the first automatic join to a newly created hotspot profile? What is the recommended supported approach for determining that the intended Wi-Fi network is genuinely connected after apply() completes? What is the most reliable way to establish that local TCP communication is ready before beginning an application-level transfer? Are there additional public diagnostic facilities or measurements that could help distinguish Wi-Fi association instability from DHCP or subsequent network-path problems? We are looking for a documented, App Store-compatible approach. We are not assuming a particular root cause and do not want to rely on private APIs or undocumented system behaviour. Any practical experience or pointers to relevant Apple documentation would be appreciated.
1
0
150
1w
URL Filter fails on macOS 27.2 beta: privacy-proxy failure on PIR status request
On macOS 27.2 beta 1/2 our URL filter never starts: the session loops starting -> stopping. The same build works on macOS 27.0 (26A428). Both our TestFlight and notarized standalone builds fail. Prefilter and PIR registration succeed. The PIR status request then fails: NWPath is satisfied, the connection is configured proxy fail closed, proxy strict fail closed, the proxy fails (event: proxy:children_failed), and the error is NSURLErrorDomain -1009 / POSIX 50 "Network is down" with _NSURLErrorPrivacyProxyFailureKey=true. NEMembershipCheckerErrorDomain Code=3 -> NEAgentURLFilterErrorDomain Code=3; the app sees serverSetupIncomplete. The privacy-proxy allow-list entry is identical on macOS 27.0 and 27.2 beta (com.adguard). Disabling the VPN, rebooting, and recreating the URL filter configuration do not help. Log excerpt: neagent: updatePrefilterWithCompletionHandler - result 1 neagent: <NEPIRChecker> - Register with PIR Server (group <com.adguard.safari.AdGuard> ... PrivacyProxyFailOpen <0> ...) -> completed registration ciphermld: [C3 ...] proxy fail closed, proxy strict fail closed ciphermld: [C3.1.1 ... failed proxy (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, flow divert agg: 2, LQM: good)] event: proxy:children_failed ciphermld: queryStatus: NSURLErrorDomain -1009 / POSIX 50 "Network is down", _NSURLErrorPrivacyProxyFailureKey=true, NWPath=satisfied neagent: Failed to startFilter <Error Domain=NEMembershipCheckerErrorDomain Code=3 "(null)"> nesessionmanager: NEURLFilterPlugin(com.adguard.safari.AdGuard[url-filter][inactive]): setStatus:error: - err Error Domain=NEAgentURLFilterErrorDomain Code=3 Filed as FB24933164.
9
2
1.2k
1w
`sysextd` rejects new `NEFilterDataProvider` activation with "no policy" on macOS 26 — despite valid Developer ID + notarization
I'm building a macOS network monitor using NEFilterDataProvider as a system extension, distributed with Developer ID signing. On macOS 26.3 (Tahoe), sysextd consistently rejects the activation request with "no policy, cannot allow apps outside /Applications" — despite the app being in /Applications and passing every verification check. I'm aware of the known Xcode NE signing bug (r. 108838909) and have followed the manual signing process from Exporting a Developer ID Network Extension. I've also tried both xcodebuild build and xcodebuild archive workflows — identical failure. Environment macOS 26.3 (25D125), SIP enabled Xcode 26.3 (17C529) Hardware Apple M2 Pro Certificate Developer ID Application (issued Jan 30, 2026 — 27 days old) MDM/Profiles None installed Signing & Verification (all pass) $ spctl -a -vv /Applications/Chakshu.app /Applications/Chakshu.app: accepted source=Notarized Developer ID origin=Developer ID Application: ROBIN SHARMA (R65679C4F3) $ codesign --verify --deep --strict -vv /Applications/Chakshu.app /Applications/Chakshu.app: valid on disk /Applications/Chakshu.app: satisfies its Designated Requirement $ xcrun stapler validate /Applications/Chakshu.app The validate action worked! App signing: Authority=Developer ID Application: ROBIN SHARMA (R65679C4F3) Authority=Developer ID Certification Authority Authority=Apple Root CA TeamIdentifier=R65679C4F3 Runtime Version=26.2.0 Notarization Ticket=stapled App entitlements: com.apple.application-identifier = R65679C4F3.dev.indrasvat.chakshu com.apple.developer.team-identifier = R65679C4F3 com.apple.developer.system-extension.install = true com.apple.developer.networking.networkextension = [content-filter-provider-systemextension] keychain-access-groups = [R65679C4F3.*] Extension signing: Same Developer ID authority, same team, same timestamp. Extension entitlements match (minus system-extension.install). Developer ID provisioning profiles are embedded in both app and extension. What sysextd logs Captured Feb 26, 2026 from log stream --predicate 'process == "sysextd"': sysextd [com.apple.sx:XPC] client activation request for dev.indrasvat.chakshu.filter sysextd attempting to realize extension with identifier dev.indrasvat.chakshu.filter sysextd (Security) SecKeyVerifySignature ← pass (×2) sysextd (Security) SecTrustEvaluateIfNecessary ← pass (×2) sysextd [com.apple.xpc:connection] activating connection: name=com.apple.CodeSigningHelper sysextd [com.apple.xpc:connection] invalidated after the last release sysextd no policy, cannot allow apps outside /Applications sysextd [com.apple.sx:XPC] client connection invalidated Signature and trust evaluation pass. CodeSigningHelper completes. Then the policy check fails. The app receives OSSystemExtensionError code 4 (extensionNotFound). What I've tried and ruled out Build process: Approach Result xcodebuild build -configuration Release + manual re-sign Same failure xcodebuild archive + export from archive + manual re-sign (per thread/737894) Same failure Minimal hand-crafted Xcode project (no xcodegen, trivial code) Same failure Both workflows follow Quinn's process exactly: build with Apple Development → copy app → embed Developer ID provisioning profiles → re-sign inside-out (extension first, then app) with -systemextension suffix entitlements → notarize → staple → install to /Applications. System-level checks: Rebooting — no change Killing sysextd — no change Removing com.apple.quarantine xattr — no change chown root:wheel on app bundle — no change lsregister -r (reset Launch Services) — no change Waiting 27 days for certificate propagation — no change Reinstalling via Finder drag-to-Applications — no change No MDM or configuration profiles installed /Library/SystemExtensions/db.plist shows extensionPolicies: [] (empty) Key observation Pre-existing network extensions activated before macOS 26 work fine on this machine. For example, Tailscale's NEPacketTunnelProvider shows state: activated_enabled in the system extensions database — it was activated on a prior macOS version and is still running. Only new system extension activations fail. I've seen similar Tahoe-specific reports from LuLu (same NEFilterDataProvider type, Developer ID distribution): LuLu #825 LuLu #831 Questions Is this a known regression in macOS 26's sysextd policy evaluation for new Developer ID system extension activations? sysextd's policy check fails after all signature and trust evaluation succeeds. Is there a separate trust/policy path that sysextd consults beyond what spctl, codesign, and CodeSigningHelper verify? Is there anything else I should be checking? I have a sysdiagnose captured immediately after the failure, a minimal reproducer project, and full raw sysextd logs available on request.
8
0
822
1w
Developer ID system extension rejected at activation: “Extension not found in App bundle”
Body: I’m building a Developer ID app (distributed outside the Mac App Store) that ships a packet-tunnel system extension. The extension fails at activation with: Extension not found in App bundle. Unable to find any matched extension with identifier: com.hawksnestsoftware.securityhawkvpn.tunnel Setup App: com.hawksnestsoftware.securityhawkvpn, Developer ID Application, team A5WW6PA8WT, hardened runtime, notarized and stapled, installed at /Applications/SecurityHawk VPN.app Extension: Contents/Library/SystemExtensions/PacketTunnel.systemextension, identifier com.hawksnestsoftware.securityhawkvpn.tunnel, CFBundlePackageType = SYSX. codesign --verify --strict passes, and the signature matches its designated requirement. Entitlements: the app has com.apple.developer.system-extension.install, and its embedded provisioning profile grants it. The extension has com.apple.developer.networking.networkextension = packet-tunnel-provider-systemextension. The app calls OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier:queue:) and the request fails with the error above. Machine: MacBookPro15,3, macOS 15.8.2 (24H232), Xcode 16.4. What I’ve ruled out Sandbox on and off (the error is the same either way) Signing and strict verification The embedded profile’s system-extension entitlement A duplicate Debug copy of the app elsewhere on disk (Spotlight finds only the /Applications copy) A restart before retesting Observed systemextensionsctl list shows no registration for the extension after the failed request. log show and log stream filtered on sysextd show no entries for the request. Question: What causes sysextd to report that it cannot find an extension in the app bundle when the bundle, identifier, and signature all look correct? Is there a required build setting or Info.plist key for a Developer ID system extension that I may be missing? Error seen: Error: “Extension not found in App bundle. Unable to find any matched extension with identifier: com.hawksnestsoftware.securityhawkvpn.tunnel” App: com.hawksnestsoftware.securityhawkvpn, Developer ID, team A5WW6PA8WT, notarized and stapled, installed at /Applications/SecurityHawk VPN.app Extension: Contents/Library/SystemExtensions/PacketTunnel.systemextension, identifier com.hawksnestsoftware.securityhawkvpn.tunnel, CFBundlePackageType SYSX, valid and matching its designated requirement Entitlements: app has com.apple.developer.system-extension.install and the embedded profile grants it; the extension has packet-tunnel-provider-systemextension Machine: MacBookPro15,3, macOS 15.8.2 (24H232), Xcode 16.4 Observed: systemextensionsctl list shows no registration; sysextd logs show nothing for the request Codesign command: denisarsenault@Deniss-MacBook-Pro-2 ~ % codesign -d --entitlements :- "/Applications/SecurityHawk VPN.app/Contents/Library/SystemExtensions/PacketTunnel.systemextension" Executable=/Applications/SecurityHawk VPN.app/Contents/Library/SystemExtensions/PacketTunnel.systemextension/Contents/MacOS/PacketTunnel warning: Specifying ':' in the path is deprecated and will not work in a future release <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.application-identifier</key><string>A5WW6PA8WT.com.hawksnestsoftware.securityhawkvpn.tunnel</string><key>com.apple.developer.networking.networkextension</key><array><string>packet-tunnel-provider-systemextension</string></array><key>com.apple.developer.team-identifier</key><string>A5WW6PA8WT</string><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.network.client</key><true/><key>com.apple.security.network.server</key><true/></dict></plist>denisarsenault@Deniss-MacBook-Pro-2 ~ %
1
0
98
1w
NETunnelProviderManager.saveToPreferences() fails with permission denied on macOS
I'm developing a macOS app using a Network Extension Packet Tunnel Provider. The System Extension activates successfully, but NETunnelProviderManager.saveToPreferences() consistently fails with permission denied. Environment macOS virtual machine running under UTM Host app and embedded Packet Tunnel System Extension signed with Developer ID App notarization verified successfully System Extension status: [activated enabled] Packet Tunnel has com.apple.security.app-sandbox=true and com.apple.security.network.client=true Host app has the Network Extension entitlement Reproduction Launch the installed, notarized HostApp. Call NETunnelProviderManager.loadAllFromPreferences(). No manager matching the Packet Tunnel provider bundle identifier is found. Create a NETunnelProviderManager. Configure NETunnelProviderProtocol with the Packet Tunnel provider bundle identifier and a server address. Set localizedDescription and isEnabled = true. Call saveToPreferences(). Observed result On October 30, 2026, the following events were recorded: 11:25:32.643 PROTOTYPE_MANAGER_CREATED 11:25:32.643 PREFERENCES_LOADED 11:25:32.643 PROTOTYPE_VPN_AUTH_SKIPPED 11:25:32.646 Saving configuration ... with existing signature (null) 11:25:33.766 NEConfigurationErrorDomain Code=10 "permission denied" 11:25:33.766 NEVPNErrorDomain Code=5 "permission denied"The app never reaches startVPNTunnel(). What I've already checked Developer ID code signing verification succeeds. Notarization and stapler validation succeed. The System Extension is activated and enabled. The failure reproduces both with and without created.loadFromPreferences() before saving. An explicit VPN authorization step is disabled in these reproduction runs. Questions What conditions can cause NEConfigurationErrorDomain Code=10 when a newly created NETunnelProviderManager is saved? Are there additional signing, entitlement, authorization, or configuration requirements for a Developer ID-distributed macOS Packet Tunnel app? Which NetworkExtension or nehelper diagnostics would help identify the specific permission check that fails? Is there any known difference in this behavior when running under macOS virtualization? I can provide a minimal reproduction project, sanitized logs, entitlement output, and a sysdiagnose privately if necessary. Thank you for your guidance.
1
0
78
1w
Local Push Connectivity: approved for development only, resubmitted for App Store — only received the automated "Network Extension (additional values)" confirmation
In August 2026 we requested the Local Push Connectivity entitlement. On September 12 we received two emails one minute apart: the automated "Network Extension (additional values) entitlement confirmation" from developer@email.apple.com, followed by a reply from Local Push Review ("Re: Requesting Network Extension App Push Entitlement") stating the request was "approved for development and testing purposes only. If and when you have a product ready for the store, please resubmit your request and include a description of your product." We built the NEAppPushProvider, tested it on the vessel's Wi-Fi, and resubmitted through the same request page on September 15. On October 20 we received only the same automated "Network Extension (additional values) entitlement confirmation" — identical wording to September 12 — and no reply from Local Push Review. Since the same automated confirmation accompanied the development-only approval, we can't tell what the October 20 assignment means. The App ID editor shows Network Extension (additional values) either way. Is our resubmission approved for App Store distribution, or is it still pending review? Our team ID is M4S46K7L33.
1
0
315
1w
macOS application renaming
Hello, We are developing a macOS application with many different components that are required for our business features. We distribute the product outside the App Store and sign it with our Developer ID certificate. Rebranding an app is a rare case, but sometimes it happens. My question is: Does Apple have any guide or recommendations on how to rebrand an app properly, other than distributing a completely new product? I am asking because our application has a complex structure: UI app (MyApp1, bundle ID = com.myApp1.osx.app) Helper tool (MyApp1HelperTool, bundle ID = com.myApp1.osx.HelperTool) Privileged daemon (MyApp1Daemon, bundle ID = com.myApp1d) System Extension, Transparent Proxy (MyApp1Proxy, bundle ID = com.myApp1.osx.proxy) As you can see, the brand name is used not only in the bundle and product names, but also in the bundle IDs. At some point, I need to change the product name from MyApp1 to MyApp2. Ideally, I would also like to change the bundle IDs to match the new brand. After rebranding, end users should not see MyApp1 anywhere in the system, only MyApp2. Also, components that are already installed and approved (System Extension, proxy configuration, helper tool, etc.) should stay approved. We would like to avoid showing the approval prompts again to all our end users. I did some research and found that bundle IDs technically cannot be changed. To solve this, I would need to release a new app and implement an in-app update mechanism that updates MyApp1 to MyApp2. However, even with a new app and an in-app update mechanism, I did not find a way to avoid user prompts for approving the new extension, the proxy, and possibly the privileged helper tool. For macOS, these will be new components that require explicit user approval. MDM is not a solution for us: some of our customers use MDM, but many of them do not. We want the update to be as smooth as possible. Thank you!
4
0
292
2w
Network Extension Resources
General: Forums subtopic: App & System Services > Networking DevForums tag: Network Extension Network Extension framework documentation Routing your VPN network traffic article Filtering Network Traffic sample code TN3120 Expected use cases for Network Extension packet tunnel providers technote TN3134 Network Extension provider deployment technote TN3165 Packet Filter is not API technote Network Extension and VPN Glossary forums post Debugging a Network Extension Provider forums post Exporting a Developer ID Network Extension forums post Network Extension Framework Entitlements forums post Network Extension vs ad hoc techniques on macOS forums post Network Extension Provider Packaging forums post NWEndpoint History and Advice forums post Extra-ordinary Networking forums post URL filter: WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension URL filters documentation Filtering traffic by URL sample code Setting up a PIR server for URL filtering sample code Using the Bloom filter tool to configure a URL filter sample code PIR Service Example open source server sample and specifically its documentation Wi-Fi management: Understanding NEHotspotConfigurationErrorInternal forums post See also Networking Resources for general networking resources, including information about Wi-Fi. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
4.3k
Activity
Aug ’26
URL Filter (Oblivious HTTP) configuration In Review for almost a week with no feedback
Hello, I submitted a Network Extension URL Filter (Oblivious HTTP) configuration in CloudKit Console almost a week ago. It still says In Review / Waiting for Approval and I haven't heard anything back since the submission notice. I wanted to check whether anything is missing on my end. Just in case, the configuration ID is 60802ed4-abfa-4b20-a64e-0d35230f478a. The app is an open-source ad and tracker blocker from the developers of an existing content blocker with a large user base. On iPhone and iPad its system-wide blocking runs entirely through the URL filter. Until the configuration is approved the iOS app can't block anything at all, and our testers are left with a Mac-only product in the meantime. Because lookups go through Apple's relay to our own PIR server, we never learn which sites anyone visits. All four endpoints have been live since the day I submitted and the TXT records are in place. Every database we build also includes the www.apple.com/url-filter-test validation entry. Is there anything else I need to provide, or a rough timeline I should expect? Thank you in advance!
Replies
0
Boosts
0
Views
23
Activity
26m
[macOS 27.2]: System-Wide DNS Resolution Failures After Sleep/Wake – mDNSResponder and NETransparentProxyProvider
Summary Recent macOS release observed intermittent system-wide DNS failures after sleep/wake on multiple devices running Global Secure Access (GSA) with NETransparentProxyProvider. Previously successful DNS lookups time out after wake across applications, including browsers and GSA. Two captures contain failure-time evidence of the mDNSResponder resolver queue predominantly waiting in close()/kernel. Other captures show similar DNS failures, but a shared root cause has not been established. Call chain, from thread entry to kernel wait: start_wqthread + 8 _pthread_wqthread + 292 _dispatch_workloop_worker_thread + 720 _dispatch_root_queue_drain_deferred_wlh + 284 _dispatch_lane_invoke + 392 _dispatch_lane_serial_drain + 332 _dispatch_source_invoke + 920 _dispatch_source_cancel_callout + 208 _dispatch_continuation_pop + 596 _dispatch_client_callout + 16 close + 8 fleh_synchronous + 72 sleh_synchronous (sleh.c:1610) unix_syscall (systemcalls.c:181) fp_close_and_unlock_with_action (kern_descrip.c:1874) fg_drop (kern_descrip.c:287) soclose (uipc_socket.c:1345) soclose_locked (uipc_socket.c:1138) cfil_sock_close_wait (content_filter.c:5743) soflow_db_apply (socket_flows.c; line unavailable) cfil_filters_udp_attached_per_flow (content_filter.c:6675) _sleep (kern_synch.c:213) lck_mtx_sleep_deadline (locks.c:1583) thread_block_reason (sched_prim.c:4060) thread_invoke (sched_prim.c:3443) Steps to reproduce The issue is intermittent. These steps describe the observed sequence, not a deterministic minimal reproduction. Run the GSA client using NETransparentProxyProvider. The affected configurations also have Microsoft Defender network extensions active. Verify that a system DNS lookup succeeds for a known hostname. Allow the Mac to sleep, including maintenance DarkWake cycles. Wake the Mac and repeat system DNS lookups or use applications requiring hostname resolution. Observe repeated approximately 30-second lookup timeouts, sometimes longer. Observed results November 5, 2026 - UTC+05:30 capture User-reported impact: Recurrence of the same sleep/wake connectivity symptoms. OS: macOS 27.2 (26B123). Incident window: 20:38-20:41 IST / 15:08-15:11 UTC. The same Chrome client/name A lookup succeeds earlier in 12.984 ms but times out after wake in 29,999.705 ms. The DNS service/server route changed, so this is not a controlled identical-network comparison. The resolver records 1,007 timeout callbacks during the incident window, across browsers, Teams, GSA, Defender and other processes. The failure-time spindump at 20:40:21.009-20:40:31.013 IST shows the original mDNSResponder PID 78534 with 715/715 resolver-queue samples under dispatch-source cancellation → close() → kernel → lck_mtx_sleep_deadline. Source: spindump.txt:75998-76093. This establishes a sampled wait, not a permanent deadlock or proof of the same root cause as November 2. The file descriptor and kernel/filter wait owner remain unidentified. A later matching Chrome lookup returns an address at 20:43:18.191816 IST on the same resolver PID, without a recorded resolver restart. This establishes some recovery, not that every application or tunnel recovered. November 2, 2026 - UTC-08:00 capture User-reported impact: No network upon wake. This eventually resolves without a reboot, after approximately 5 to 15 minutes of waiting. OS: macOS 27.2 (26B123). Incident window: 09:40-09:45 PST / 17:40-17:45 UTC. The same Edge A lookup succeeds before sleep in 19.346 ms but times out after wake in 29,999.826 ms. The resolver records 1,403 timeout callbacks during the incident window. The failure-time spindump shows 770/777 resolver-queue samples under dispatch-source cancellation → close() → kernel; 769 include lck_mtx_sleep_deadline. This establishes a dominant sampled wait, not a permanent deadlock. The file descriptor and kernel/filter wait owner remain unidentified. November 3, 2026 - UTC-08:00 capture (Mihai) Evidence: mihai_gsa_error.tar.gz The following example records a failure resolving GSA’s own control-plane endpoint, whose DNS lookup is not intercepted by the GSA tunnel. Times in these excerpts are local (UTC-08:00). GSA error [2026-11-03 10:13:58.463] Network connection to the Global Secure Access Edge could not be established StreamId: ControlStream Hostname: <tenant>.auth.client.globalsecureaccess.microsoft.com:443 Error: hostname lookup error: Address lookup failed os_error: nodename nor servname provided, or not known syscall: getaddrinfo mDNSResponder records 10:13:19.663661 [R125367->DupQ50990->Q38408] Duplicate question <private> dn:04wpeA (Addr) 10:13:58.468519 [R125367] DNSServiceQueryRecord STOP -- name hash: dn:04wpeA, duration: 39s 10:13:59.078847 [R125340] QueryRecordOpCallback: Question <private> dn:04wpeA (Addr) timing out, InterfaceID 0x0 Additional observations The original resolver records 11 timeout callbacks across GSA, Defender, Spotify and the system time service. A GSA A-query returns a positive result in 1.282 ms earlier (cache-compatible, not a cold upstream baseline), then the same client/name/qtype/flags times out after 41.865784 wall-clock seconds; that interval includes sleep. The DNS service/server set changes, so this is not a controlled same-network comparison. At 09:40 PST the Wi-Fi interface becomes inactive and loses its IPv4 address, followed by no-dns-service results. The first native lookup errors precede this link loss; it does not explain the entire case. Four GSA A/AAAA timeout transactions have matching late UDP replies. For one A-query, the reply is logged 25.095999 seconds after its matching send and 7.197434 seconds after the API timeout, during shutdown. 48 acceptable UDP response records appear within 1.467 ms. The location of the delay is not identified.
Replies
5
Boosts
1
Views
299
Activity
49m
Is it safe to strip with All Symbols for a content filter?
We would like to minimise the amount of code exposed in the product we have developed and an obvious option is to configure our build setting to use the All Symbols for Strip Style. Some investigation with an AI tool reports there are possible problems doing so. ContentFilter: non-global → all — risky. The NetworkExtension and XPC subsystems load your bundle and look up classes by name through the ObjC runtime, which uses __objc_classlist and friends (not the Mach-O symbol table), so in principle all works. In practice it occasionally breaks bundle loading in edge cases. If you try this, test specifically that systemextensionsctl activates the bundle and the filter actually traps packets. Is it safe to use All Symbols with a content filter or do we need to accept Non-Global symbols? Thanks, Dave
Replies
1
Boosts
0
Views
124
Activity
4h
NETransparentProxyManager: saving isOnDemandEnabled = true disables On-Demand on other proxies
On macOS, multiple NETransparentProxyManager (NEAppProxyProvider) configurations from different vendors can be enabled (isEnabled = true) and run simultaneously. However, we discovered that when one NETransparentProxyManager configuration calls saveToPreferencesWithCompletionHandler: with isOnDemandEnabled = true, /usr/libexec/nehelper (NEConfigurationManager) silently modifies any other enabled NETransparentProxyManager configuration in /Library/Preferences/com.apple.networkextension.plist and flips its OnDemandEnabled to false (and nesessionmanager logs Resetting VPN On Demand and marks the other session not-kernel-activated). Unlike NEVPNManager.isEnabled (which documents mutual exclusion for personal VPNs), NETransparentProxyManager is designed so multiple transparent proxies can coexist simultaneously, and neither NETransparentProxyManager.h nor NEVPNManager.h documents that isOnDemandEnabled is mutually exclusive across coexisting transparent proxy configurations. Root Cause Observed in NetworkExtension.framework When inspecting -[NEConfigurationManager saveConfigurationToDisk:updateSCPreferences:currentSignature:userUUID:notifyNow:isUpgrade:], when iterating over existing NEConfiguration objects of the same grade: If [[newConfig VPN] isEnabled] && [[otherConfig VPN] isEnabled] && [[newConfig VPN] isOnDemandEnabled] && [[otherConfig VPN] isOnDemandEnabled], NEConfigurationManager invokes: +[NEConfigurationManager disableConfiguration:otherConfig onDemandOnly:YES] disableConfiguration:onDemandOnly:YES calls [[otherConfig VPN] setOnDemandEnabled:NO], even when both configurations are NETransparentProxyManager (TunnelType == 2). Real-World Impact When two enterprise security products that both use NETransparentProxyManager are installed on the same Mac: Both configure isEnabled = true, onDemandRules = [NEOnDemandRuleConnect()], and isOnDemandEnabled = true. Whenever Proxy A saves its preferences, nehelper silently flips Proxy B's isOnDemandEnabled to false (and vice versa). After a reboot or network transition where Proxy B's initial startVPNTunnel fails while Wi-Fi is still associating and Proxy B relies on VPN On Demand (NEOnDemandRuleConnect) to start its NEAppProxyProvider once network connectivity comes up, macOS never starts Proxy B because its isOnDemandEnabled flag was cleared. Minimal Reproducer (Swift) Compile this minimal CLI inside an app bundle signed with the com.apple.developer.networking.networkextension = ["app-proxy-provider"] entitlement: import Foundation import NetworkExtension let args = CommandLine.arguments let name = args.count > 1 ? args[1] : "PocProxyA" let action = args.count > 2 ? args[2] : "status" DispatchQueue.main.async { NETransparentProxyManager.loadAllFromPreferences { managers, error in if let error = error { print("[\(name)] loadAllFromPreferences error: \(error)") exit(1) } let all = managers ?? [] let existing = all.first(where: { $0.localizedDescription == name }) if action == "status" { if let mgr = existing { print("[\(name)] -> isEnabled=\(mgr.isEnabled), isOnDemandEnabled=\(mgr.isOnDemandEnabled), rulesCount=\(mgr.onDemandRules?.count ?? 0)") } else { print("[\(name)] -> not found") } exit(0) } if action == "remove" { guard let mgr = existing else { exit(0) } mgr.removeFromPreferences { err in print("[\(name)] removed (err=\(String(describing: err)))") exit(0) } return } // action == "save" let mgr = existing ?? NETransparentProxyManager() let proto = (mgr.protocolConfiguration as? NETunnelProviderProtocol) ?? NETunnelProviderProtocol() proto.providerBundleIdentifier = "com.example.poc.extension" proto.serverAddress = "127.0.0.1" mgr.protocolConfiguration = proto mgr.localizedDescription = name mgr.isEnabled = true mgr.onDemandRules = [NEOnDemandRuleConnect()] mgr.isOnDemandEnabled = true print("[\(name)] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true...") mgr.saveToPreferences { err in if let err = err { print("[\(name)] saveToPreferences error: \(err)") exit(1) } print("[\(name)] saveToPreferences succeeded! isEnabled=\(mgr.isEnabled), isOnDemandEnabled=\(mgr.isOnDemandEnabled)") exit(0) } } } RunLoop.main.run()Reproduction Output Running save on PocProxyA, then save on PocProxyB, and checking status on both: === Step 1: PocProxyA saves isOnDemandEnabled = true === [PocProxyA] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyA] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true [PocProxyA] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 === Step 2: PocProxyB saves isOnDemandEnabled = true === [PocProxyB] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyB] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true === Step 3: Check BOTH configurations after PocProxyB saved === [PocProxyA] -> isEnabled=true, isOnDemandEnabled=false, rulesCount=1 [PocProxyB] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 === Step 4: PocProxyA saves isOnDemandEnabled = true again === [PocProxyA] Saving NETransparentProxyManager with isEnabled=true, isOnDemandEnabled=true... [PocProxyA] saveToPreferences succeeded! isEnabled=true, isOnDemandEnabled=true === Step 5: Check BOTH configurations after PocProxyA saved === [PocProxyA] -> isEnabled=true, isOnDemandEnabled=true, rulesCount=1 [PocProxyB] -> isEnabled=true, isOnDemandEnabled=false, rulesCount=1Questions Is disableConfiguration:onDemandOnly:YES stripping isOnDemandEnabled across coexisting NETransparentProxyManager (TunnelType = 2) configurations a bug in NEConfigurationManager, or an intentional limitation? Is there a recommended way for two coexisting NETransparentProxyManager configurations from different vendors to both use On-Demand without disabling each other's isOnDemandEnabled flag on saveToPreferences? Filed in Feedback Assistant as FB25463155.
Replies
3
Boosts
2
Views
286
Activity
1d
NEAppPushProvider times out connecting to a server on a routed subnet, while the containing app connects fine
We use Local Push Connectivity (NEAppPushProvider, matchSSIDs set) to receive notifications from an on-premise MQTT broker over WebSocket (wss://host:port/mqtt). iPhone on Wi-Fi, VLAN A (SSID matches matchSSIDs) Server on wired VLAN B, routing and firewall rules allow VLAN A → VLAN B on that port Result: the containing app, in the foreground, connects successfully to wss://<VLAN B IP>:<port>/mqtt. At the same moment, the app push provider (URLSessionWebSocketTask to the exact same URL) fails with "The request timed out". The provider starts normally (start() is called). When the server has an address on the Wi-Fi subnet (VLAN A), the provider connects without any issue. Is the app push provider restricted to servers on the local subnet of the matched Wi-Fi network? If so, is this documented anywhere? If not, what could prevent the provider from reaching a routed address that the app itself can reach? iOS version: 27.0.1 device : iPhone 13
Replies
1
Boosts
0
Views
78
Activity
1d
NEURLFilterManager: inconsistent per-domain blocking (some sites never block, one flaps) - confirmed PIR database is correct
Hello, Some context: DropBet is an app that helps people with gambling addiction stay off gambling sites and apps, using NEURLFilterManager/PIR to block a large list of known gambling domains system-wide. For a lot of our users this filter is a core part of their recovery > reliability really matters here. Since fixing an unrelated HPKE encryption bug (separate thread, now closed), the filter works end-to-end for the first time, but blocking is inconsistent per domain in a way I can't explain from my side: winamax.fr and the Winamax app: blocked reliably, every single time > clean "connection failed" style block, confirmed to load fine with protection off. unibet.fr and betclic.fr: never blocked, consistently > confirmed even after a full device reboot (rules out stale caching), and confirmed identical across both Safari and Chrome on iOS tested side-by-side (so not browser-specific). olybet.fr: flaps > the page reloads every 2-3 seconds with protection on, also identical across both browsers. Confirmed this only happens with the filter enabled (tested toggling protection off/on against the same page). unibet.fr auto-redirects into the native Unibet app via a Universal Link before the page loads, unlike betclic.fr which stays in the browser > different code path, possibly relevant. To rule out any issue on our end, I wrote a standalone test that queries our deployed PIR database shards directly - bypassing OHTTP, the app, and the device entirely - for all of the domains above plus their www. variants. All of them correctly return the blocked value, no exceptions, including unibet.fr and betclic.fr which never block on the actual device. So the database, the PIR protocol implementation, and the server are confirmed correct for every domain I've tested. This points at something in how NEURLFilterManager/ciphermld applies a correctly-received PIR verdict on-device - possibly related to query batching, an evaluation-key edge case, or Universal Link handling bypassing the filter before a web request is even made. Is there anything you can share about how the client applies results once decrypted, or known issues around any of this?
Replies
5
Boosts
0
Views
126
Activity
1d
NEURLFilter configuration still "Queued" six weeks after submission
Our Network Extension URL Filter configurations in CloudKit Identity & Trust are not moving through onboarding. STG: configuration 6e17673d-dbaa-4b35-98c5-ff9e7a357577, bundle ca.itellyou.stg. Submitted 2026-09-25, status Approved, Onboarding Status "Queued". PRD: configuration 06fa2558-281b-4b55-b59f-402ecf359d18, bundle ca.itellyou. Submitted 2026-10-20, status In Review. Evidence (iPhone 17 Pro Max, 2026-11-06, same commit, same server, same user token): Development-signed build: the filter reaches "running" and blocks our test domains. Ad-hoc (distribution-signed) build: it cycles starting -> stopped with NEURLFilterManager.Error 9. The PIR server, Privacy Pass issuer and OHTTP gateway are live, and the test entry www.apple.com/url-filter-test is present. An Apple engineer confirmed on GitHub (apple/pir-service-example#185) that nothing is pending on our side. We also opened support case 30000007408474. Has anyone seen how long onboarding takes these days, or found a way to get it moving?
Replies
1
Boosts
0
Views
80
Activity
2d
Egress addresses of the URL filter OHTTP relay
Hello, I am wondering about the egress addresses of the Oblivious HTTP relay that Apple runs for Network Extension URL filters. I am building an iOS app that uses NEURLFilterManager. The app builds a Bloom filter from the block lists a user picks. The system only asks our server about a site when that filter has a hit. Each lookup is encrypted with keyword PIR and carries a Privacy Pass token instead of anything tied to the user. It reaches our server through your relay, which strips the device's address. We run our own PIR server, Privacy Pass issuer and OHTTP gateway instead of a hosted service. The gateway is the one part of the setup that should only ever hear from your relay. Since every real lookup comes through the relay, I would really like to drop all other traffic to it at the firewall. Right now I can't do that. I also can't rate limit by address because every legitimate request shares the relay's addresses. As a result the gateway just has to stay open to everyone and rely on global limits, which is a far cry from what I'd want for a service that only one client is meant to reach. I have three questions about this. 1) Are the relay's egress address ranges published somewhere, or can they be shared with developers who have been onboarded? 2) If they are shared, how would we find out when they change and how much notice there is? 3) If the addresses can't be shared, is there another way to tell that a request came from the relay, such as a header or a client certificate? Please let me know if any of this is unclear or if there is a better place to ask. Thank you in advance, Alexander
Replies
0
Boosts
0
Views
62
Activity
2d
Apple thought it was impossible
Apple thought it was impossible. I made it possible. No server. Just an iPhone. LUMEN-JEV OS v3.0 — On-device OS using Pyto + iCloud Drive + Obsidian Architecture: Pyto runtime = server: Persistent loop, 922 tickers scanned, 502.6 ev/s, 12ms latency, sub-2ms cache iCloud Drive = bus: Writes JEV-BUS.md every 15s, shared working directory Obsidian = OS window manager: 00-JEV-DASHBOARD-main 48 nodes live Vault: 11/11 LOCKED, Factory Complete Anchor: 572b9df5e8e1f101365f8316ba7b34da4aa54ff89a2dcdb68ed20b126e8cabed Chain: REAL-EXCHANGE-PUBLIC-WS -> 8-MODULE-DEMO -> DEMO-TERMINATED -> NO EXECUTION Feed: real-public-readonly / public_ticker_only Modules (8-MODULE-v1px): WARREN-WATCHDOG, KEEPER-BOX, NODE-MODE-SYNC, VAULT-MULT, SCOUT-SCAN, SIREN-FILTER, FOCUS-SIGNAL-20K, ORACLE-PRICE-FEED, RELAY-ROUTER, AKE-ARBITRAGE, YIELD-BACK-4, MEDUSAs: 03 DYNAMIC OBSERVER-SPACE Context: Built in 33hrs over 11 nights, day job, single dad, solo dev, on iPhone only. Pyto working directory set to iCloud Drive. No Mac backend, no CloudKit function, no external server. Why this matters for iOS: Apple's sandbox says you can't run a persistent OS-like loop with live file sync on iOS. Pyto + iCloud Drive persistence proves you can. iPhone becomes the server. Proof: 48 NODES LIVE canvas PROOF CHAIN 11/11 FLAT VIEW VAULT LOCKED Jev.py V2.6 CLEAN BUS log (checked 50/100/150/200 -> 922/922 passes) Anchor hash matches zip JEV-OS-v3.0-572b9df5-40files.zip Requesting: Guidance on showcasing this as an iOS innovation + Ask Apple office hours. X proof pinned: @Activepython007
Replies
22
Boosts
1
Views
1.3k
Activity
4d
Is a `flowClosed` report guaranteed when the owning process exits or crashes?
Our macOS NEFilterDataProvider sets shouldReport = true on flow verdicts and receives NEFilterReport.Event.flowClosed in handle(_:). In testing, we have observed close reports after the owning process exits or crashes, sometimes with a short delay. Is a flowClosed report guaranteed for every TCP and UDP flow in these cases? Does the behavior differ by protocol, and is there a documented upper bound on delivery time? We also set statisticsReportFrequency = .low. Does that setting affect only periodic .statistics reports, with no effect on flowClosed delivery?
Replies
2
Boosts
0
Views
109
Activity
5d
NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hello ! following up from a related thread (account transfer issue, now resolved: https://developer.apple.com/forums/thread/843546?answerId=911820022), but this is a distinct, new issue so starting fresh as suggested. The extension launches fine, XPC handshake succeeds, and PIR registration completes successfully. But the subsequent NEPIRChecker status check fails every time (retried repeatedly over several minutes, same result each time): PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x677037cf0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}>Config being registered (confirmed from the logs): pirServerURL = https://pir.dropbet.app/ pirPrivacyPassIssuerURL = https://pir.dropbet.app/issueBoth endpoints are live and were already validated as part of the original NEURL Filter configuration approval. I've captured a sysdiagnose from the device right when this was happening, so I have that ready to attach to a bug report if useful — just let me know and I'll file one. Any idea what CipherML error 1100/1800 typically indicates?
Replies
8
Boosts
0
Views
487
Activity
6d
Cannot open Chrome UDP flows in Transparent Proxy Provider
We are implementing a Transparent Proxy for HTTPS (via TCP and QUIC). The following rules are set in startProxy: settings.includedNetworkRules = [ NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "443"), prefix: 0, protocol: .TCP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "::", port: "443"), prefix: 0, protocol: .TCP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "443"), prefix: 0, protocol: .UDP), NENetworkRule(destinationNetwork: NWHostEndpoint(hostname: "::", port: "443"), prefix: 0, protocol: .UDP) ] Handling TCP connections seems to work fine. But opening UDP flows from Chrome (or Brave) always fails with Error Domain=NEAppProxyFlowErrorDomain Code=2 "The peer closed the flow" (Doing the same for Firefox works!) BTW: We first create a remote UDP connection (using the Network framework) and when it is in the ready state, we use connection?.currentPath?.localEndpoint as the localEndpoint parameter in the open method of the flow. Is it a known issue that QUIC connections from Chrome cannot be handled by a Transparent Proxy Provider?
Replies
11
Boosts
0
Views
1.6k
Activity
1w
iPadOS: Intermittent disconnection after NEHotspotConfigurationManager automatic hotspot join
Background We are developing Share&Share, an offline device-to-device content transfer application. An iPad automatically joins a nearby Samsung Android LocalOnlyHotspot. The hotspot credentials are delivered through an authenticated, encrypted Bluetooth Low Energy (BLE) session. On iPadOS, our application decrypts the credentials natively in Swift and uses NEHotspotConfigurationManager.apply() to join the hotspot. We are investigating an intermittent connection problem during the initial automatic join. We have also submitted a private report through Apple Feedback Assistant: Feedback ID: FB25408475 Test environment Receiver: Physical iPad with a Home button. Sender/hotspot: Samsung SM-E055F. Android version: Android 16. Hotspot security: WPA2/WPA3 transition configuration. iOS implementation: Swift and NetworkExtension. joinOnce = false. The hidden property is not explicitly set. Observed behaviour Two independently instrumented automatic-join sessions showed a similar sequence: A1: The iPad associates with the Samsung hotspot and completes the WPA3 authentication exchange recorded by the Samsung. Approximately 3.35 seconds after the iPad-side join completion, iOS records a beacon-loss/roam declaration and the connection drops. A2: iOS attempts to reconnect, but the authentication exchange does not complete. A3: iOS automatically reconnects successfully, obtains a DHCP address and remains connected during the observation period. The same encrypted credentials work during both the initial and subsequent successful attempts. The apply() completion handler returns without an error. We understand that this does not establish that the device has joined successfully or that local IP connectivity is ready. What we have investigated The first join used cached beacon information approximately eight seconds old; the subsequent successful join used fresh scan information. AWDL activity was observed, but we have not established a causal relationship. Location Services scanning does not explain the first failure in our second instrumented session. The diagnostic label "Beacons Lost" is not being treated as proof of actual missed beacon frames. We have not independently established which WPA mode the iPad negotiated. We have not yet measured TCP readiness during the failed and successful attempts. We do not currently have a standalone minimal Xcode reproduction project. The behaviour was observed using our Flutter-based iOS probe and physical devices. Questions for developers familiar with NetworkExtension Has anyone observed intermittent first-join instability with NEHotspotConfigurationManager when joining a newly created Android LocalOnlyHotspot using WPA2/WPA3 transition mode? Are there documented limitations or known issues involving the first automatic join to a newly created hotspot profile? What is the recommended supported approach for determining that the intended Wi-Fi network is genuinely connected after apply() completes? What is the most reliable way to establish that local TCP communication is ready before beginning an application-level transfer? Are there additional public diagnostic facilities or measurements that could help distinguish Wi-Fi association instability from DHCP or subsequent network-path problems? We are looking for a documented, App Store-compatible approach. We are not assuming a particular root cause and do not want to rely on private APIs or undocumented system behaviour. Any practical experience or pointers to relevant Apple documentation would be appreciated.
Replies
1
Boosts
0
Views
150
Activity
1w
URL Filter fails on macOS 27.2 beta: privacy-proxy failure on PIR status request
On macOS 27.2 beta 1/2 our URL filter never starts: the session loops starting -> stopping. The same build works on macOS 27.0 (26A428). Both our TestFlight and notarized standalone builds fail. Prefilter and PIR registration succeed. The PIR status request then fails: NWPath is satisfied, the connection is configured proxy fail closed, proxy strict fail closed, the proxy fails (event: proxy:children_failed), and the error is NSURLErrorDomain -1009 / POSIX 50 "Network is down" with _NSURLErrorPrivacyProxyFailureKey=true. NEMembershipCheckerErrorDomain Code=3 -> NEAgentURLFilterErrorDomain Code=3; the app sees serverSetupIncomplete. The privacy-proxy allow-list entry is identical on macOS 27.0 and 27.2 beta (com.adguard). Disabling the VPN, rebooting, and recreating the URL filter configuration do not help. Log excerpt: neagent: updatePrefilterWithCompletionHandler - result 1 neagent: <NEPIRChecker> - Register with PIR Server (group <com.adguard.safari.AdGuard> ... PrivacyProxyFailOpen <0> ...) -> completed registration ciphermld: [C3 ...] proxy fail closed, proxy strict fail closed ciphermld: [C3.1.1 ... failed proxy (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, flow divert agg: 2, LQM: good)] event: proxy:children_failed ciphermld: queryStatus: NSURLErrorDomain -1009 / POSIX 50 "Network is down", _NSURLErrorPrivacyProxyFailureKey=true, NWPath=satisfied neagent: Failed to startFilter <Error Domain=NEMembershipCheckerErrorDomain Code=3 "(null)"> nesessionmanager: NEURLFilterPlugin(com.adguard.safari.AdGuard[url-filter][inactive]): setStatus:error: - err Error Domain=NEAgentURLFilterErrorDomain Code=3 Filed as FB24933164.
Replies
9
Boosts
2
Views
1.2k
Activity
1w
`sysextd` rejects new `NEFilterDataProvider` activation with "no policy" on macOS 26 — despite valid Developer ID + notarization
I'm building a macOS network monitor using NEFilterDataProvider as a system extension, distributed with Developer ID signing. On macOS 26.3 (Tahoe), sysextd consistently rejects the activation request with "no policy, cannot allow apps outside /Applications" — despite the app being in /Applications and passing every verification check. I'm aware of the known Xcode NE signing bug (r. 108838909) and have followed the manual signing process from Exporting a Developer ID Network Extension. I've also tried both xcodebuild build and xcodebuild archive workflows — identical failure. Environment macOS 26.3 (25D125), SIP enabled Xcode 26.3 (17C529) Hardware Apple M2 Pro Certificate Developer ID Application (issued Jan 30, 2026 — 27 days old) MDM/Profiles None installed Signing & Verification (all pass) $ spctl -a -vv /Applications/Chakshu.app /Applications/Chakshu.app: accepted source=Notarized Developer ID origin=Developer ID Application: ROBIN SHARMA (R65679C4F3) $ codesign --verify --deep --strict -vv /Applications/Chakshu.app /Applications/Chakshu.app: valid on disk /Applications/Chakshu.app: satisfies its Designated Requirement $ xcrun stapler validate /Applications/Chakshu.app The validate action worked! App signing: Authority=Developer ID Application: ROBIN SHARMA (R65679C4F3) Authority=Developer ID Certification Authority Authority=Apple Root CA TeamIdentifier=R65679C4F3 Runtime Version=26.2.0 Notarization Ticket=stapled App entitlements: com.apple.application-identifier = R65679C4F3.dev.indrasvat.chakshu com.apple.developer.team-identifier = R65679C4F3 com.apple.developer.system-extension.install = true com.apple.developer.networking.networkextension = [content-filter-provider-systemextension] keychain-access-groups = [R65679C4F3.*] Extension signing: Same Developer ID authority, same team, same timestamp. Extension entitlements match (minus system-extension.install). Developer ID provisioning profiles are embedded in both app and extension. What sysextd logs Captured Feb 26, 2026 from log stream --predicate 'process == "sysextd"': sysextd [com.apple.sx:XPC] client activation request for dev.indrasvat.chakshu.filter sysextd attempting to realize extension with identifier dev.indrasvat.chakshu.filter sysextd (Security) SecKeyVerifySignature ← pass (×2) sysextd (Security) SecTrustEvaluateIfNecessary ← pass (×2) sysextd [com.apple.xpc:connection] activating connection: name=com.apple.CodeSigningHelper sysextd [com.apple.xpc:connection] invalidated after the last release sysextd no policy, cannot allow apps outside /Applications sysextd [com.apple.sx:XPC] client connection invalidated Signature and trust evaluation pass. CodeSigningHelper completes. Then the policy check fails. The app receives OSSystemExtensionError code 4 (extensionNotFound). What I've tried and ruled out Build process: Approach Result xcodebuild build -configuration Release + manual re-sign Same failure xcodebuild archive + export from archive + manual re-sign (per thread/737894) Same failure Minimal hand-crafted Xcode project (no xcodegen, trivial code) Same failure Both workflows follow Quinn's process exactly: build with Apple Development → copy app → embed Developer ID provisioning profiles → re-sign inside-out (extension first, then app) with -systemextension suffix entitlements → notarize → staple → install to /Applications. System-level checks: Rebooting — no change Killing sysextd — no change Removing com.apple.quarantine xattr — no change chown root:wheel on app bundle — no change lsregister -r (reset Launch Services) — no change Waiting 27 days for certificate propagation — no change Reinstalling via Finder drag-to-Applications — no change No MDM or configuration profiles installed /Library/SystemExtensions/db.plist shows extensionPolicies: [] (empty) Key observation Pre-existing network extensions activated before macOS 26 work fine on this machine. For example, Tailscale's NEPacketTunnelProvider shows state: activated_enabled in the system extensions database — it was activated on a prior macOS version and is still running. Only new system extension activations fail. I've seen similar Tahoe-specific reports from LuLu (same NEFilterDataProvider type, Developer ID distribution): LuLu #825 LuLu #831 Questions Is this a known regression in macOS 26's sysextd policy evaluation for new Developer ID system extension activations? sysextd's policy check fails after all signature and trust evaluation succeeds. Is there a separate trust/policy path that sysextd consults beyond what spctl, codesign, and CodeSigningHelper verify? Is there anything else I should be checking? I have a sysdiagnose captured immediately after the failure, a minimal reproducer project, and full raw sysextd logs available on request.
Replies
8
Boosts
0
Views
822
Activity
1w
Developer ID system extension rejected at activation: “Extension not found in App bundle”
Body: I’m building a Developer ID app (distributed outside the Mac App Store) that ships a packet-tunnel system extension. The extension fails at activation with: Extension not found in App bundle. Unable to find any matched extension with identifier: com.hawksnestsoftware.securityhawkvpn.tunnel Setup App: com.hawksnestsoftware.securityhawkvpn, Developer ID Application, team A5WW6PA8WT, hardened runtime, notarized and stapled, installed at /Applications/SecurityHawk VPN.app Extension: Contents/Library/SystemExtensions/PacketTunnel.systemextension, identifier com.hawksnestsoftware.securityhawkvpn.tunnel, CFBundlePackageType = SYSX. codesign --verify --strict passes, and the signature matches its designated requirement. Entitlements: the app has com.apple.developer.system-extension.install, and its embedded provisioning profile grants it. The extension has com.apple.developer.networking.networkextension = packet-tunnel-provider-systemextension. The app calls OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier:queue:) and the request fails with the error above. Machine: MacBookPro15,3, macOS 15.8.2 (24H232), Xcode 16.4. What I’ve ruled out Sandbox on and off (the error is the same either way) Signing and strict verification The embedded profile’s system-extension entitlement A duplicate Debug copy of the app elsewhere on disk (Spotlight finds only the /Applications copy) A restart before retesting Observed systemextensionsctl list shows no registration for the extension after the failed request. log show and log stream filtered on sysextd show no entries for the request. Question: What causes sysextd to report that it cannot find an extension in the app bundle when the bundle, identifier, and signature all look correct? Is there a required build setting or Info.plist key for a Developer ID system extension that I may be missing? Error seen: Error: “Extension not found in App bundle. Unable to find any matched extension with identifier: com.hawksnestsoftware.securityhawkvpn.tunnel” App: com.hawksnestsoftware.securityhawkvpn, Developer ID, team A5WW6PA8WT, notarized and stapled, installed at /Applications/SecurityHawk VPN.app Extension: Contents/Library/SystemExtensions/PacketTunnel.systemextension, identifier com.hawksnestsoftware.securityhawkvpn.tunnel, CFBundlePackageType SYSX, valid and matching its designated requirement Entitlements: app has com.apple.developer.system-extension.install and the embedded profile grants it; the extension has packet-tunnel-provider-systemextension Machine: MacBookPro15,3, macOS 15.8.2 (24H232), Xcode 16.4 Observed: systemextensionsctl list shows no registration; sysextd logs show nothing for the request Codesign command: denisarsenault@Deniss-MacBook-Pro-2 ~ % codesign -d --entitlements :- "/Applications/SecurityHawk VPN.app/Contents/Library/SystemExtensions/PacketTunnel.systemextension" Executable=/Applications/SecurityHawk VPN.app/Contents/Library/SystemExtensions/PacketTunnel.systemextension/Contents/MacOS/PacketTunnel warning: Specifying ':' in the path is deprecated and will not work in a future release <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.application-identifier</key><string>A5WW6PA8WT.com.hawksnestsoftware.securityhawkvpn.tunnel</string><key>com.apple.developer.networking.networkextension</key><array><string>packet-tunnel-provider-systemextension</string></array><key>com.apple.developer.team-identifier</key><string>A5WW6PA8WT</string><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.network.client</key><true/><key>com.apple.security.network.server</key><true/></dict></plist>denisarsenault@Deniss-MacBook-Pro-2 ~ %
Replies
1
Boosts
0
Views
98
Activity
1w
NETunnelProviderManager.saveToPreferences() fails with permission denied on macOS
I'm developing a macOS app using a Network Extension Packet Tunnel Provider. The System Extension activates successfully, but NETunnelProviderManager.saveToPreferences() consistently fails with permission denied. Environment macOS virtual machine running under UTM Host app and embedded Packet Tunnel System Extension signed with Developer ID App notarization verified successfully System Extension status: [activated enabled] Packet Tunnel has com.apple.security.app-sandbox=true and com.apple.security.network.client=true Host app has the Network Extension entitlement Reproduction Launch the installed, notarized HostApp. Call NETunnelProviderManager.loadAllFromPreferences(). No manager matching the Packet Tunnel provider bundle identifier is found. Create a NETunnelProviderManager. Configure NETunnelProviderProtocol with the Packet Tunnel provider bundle identifier and a server address. Set localizedDescription and isEnabled = true. Call saveToPreferences(). Observed result On October 30, 2026, the following events were recorded: 11:25:32.643 PROTOTYPE_MANAGER_CREATED 11:25:32.643 PREFERENCES_LOADED 11:25:32.643 PROTOTYPE_VPN_AUTH_SKIPPED 11:25:32.646 Saving configuration ... with existing signature (null) 11:25:33.766 NEConfigurationErrorDomain Code=10 "permission denied" 11:25:33.766 NEVPNErrorDomain Code=5 "permission denied"The app never reaches startVPNTunnel(). What I've already checked Developer ID code signing verification succeeds. Notarization and stapler validation succeed. The System Extension is activated and enabled. The failure reproduces both with and without created.loadFromPreferences() before saving. An explicit VPN authorization step is disabled in these reproduction runs. Questions What conditions can cause NEConfigurationErrorDomain Code=10 when a newly created NETunnelProviderManager is saved? Are there additional signing, entitlement, authorization, or configuration requirements for a Developer ID-distributed macOS Packet Tunnel app? Which NetworkExtension or nehelper diagnostics would help identify the specific permission check that fails? Is there any known difference in this behavior when running under macOS virtualization? I can provide a minimal reproduction project, sanitized logs, entitlement output, and a sysdiagnose privately if necessary. Thank you for your guidance.
Replies
1
Boosts
0
Views
78
Activity
1w
Local Push Connectivity: approved for development only, resubmitted for App Store — only received the automated "Network Extension (additional values)" confirmation
In August 2026 we requested the Local Push Connectivity entitlement. On September 12 we received two emails one minute apart: the automated "Network Extension (additional values) entitlement confirmation" from developer@email.apple.com, followed by a reply from Local Push Review ("Re: Requesting Network Extension App Push Entitlement") stating the request was "approved for development and testing purposes only. If and when you have a product ready for the store, please resubmit your request and include a description of your product." We built the NEAppPushProvider, tested it on the vessel's Wi-Fi, and resubmitted through the same request page on September 15. On October 20 we received only the same automated "Network Extension (additional values) entitlement confirmation" — identical wording to September 12 — and no reply from Local Push Review. Since the same automated confirmation accompanied the development-only approval, we can't tell what the October 20 assignment means. The App ID editor shows Network Extension (additional values) either way. Is our resubmission approved for App Store distribution, or is it still pending review? Our team ID is M4S46K7L33.
Replies
1
Boosts
0
Views
315
Activity
1w
macOS application renaming
Hello, We are developing a macOS application with many different components that are required for our business features. We distribute the product outside the App Store and sign it with our Developer ID certificate. Rebranding an app is a rare case, but sometimes it happens. My question is: Does Apple have any guide or recommendations on how to rebrand an app properly, other than distributing a completely new product? I am asking because our application has a complex structure: UI app (MyApp1, bundle ID = com.myApp1.osx.app) Helper tool (MyApp1HelperTool, bundle ID = com.myApp1.osx.HelperTool) Privileged daemon (MyApp1Daemon, bundle ID = com.myApp1d) System Extension, Transparent Proxy (MyApp1Proxy, bundle ID = com.myApp1.osx.proxy) As you can see, the brand name is used not only in the bundle and product names, but also in the bundle IDs. At some point, I need to change the product name from MyApp1 to MyApp2. Ideally, I would also like to change the bundle IDs to match the new brand. After rebranding, end users should not see MyApp1 anywhere in the system, only MyApp2. Also, components that are already installed and approved (System Extension, proxy configuration, helper tool, etc.) should stay approved. We would like to avoid showing the approval prompts again to all our end users. I did some research and found that bundle IDs technically cannot be changed. To solve this, I would need to release a new app and implement an in-app update mechanism that updates MyApp1 to MyApp2. However, even with a new app and an in-app update mechanism, I did not find a way to avoid user prompts for approving the new extension, the proxy, and possibly the privileged helper tool. For macOS, these will be new components that require explicit user approval. MDM is not a solution for us: some of our customers use MDM, but many of them do not. We want the update to be as smooth as possible. Thank you!
Replies
4
Boosts
0
Views
292
Activity
2w