An app can be inside a sandbox and still reach a service that makes decisions on its behalf. The interesting question is what that service believes about its caller.

While reviewing macOS, I followed that question into PPPController, the component inside configd that manages legacy PPP connections. The investigation reached a privileged VPN process from App Sandbox. Separate tests also redirected L2TP connection attempts to a listener I controlled.

Apple credits this work under CVE-2026-112542 in its macOS Sequoia 15.8.2 security advisory. Apple describes a permission issue with potential network interception impact and says it added restrictions. This note explains the historical tests behind my report, including the limits that matter when describing the blast radius. Apple’s advisory

The case
CVE-2026-112542
System boundary
App Sandbox → VPN controlExisting PPP/L2TP service required
Public advisory
Apple · pppmacOS Sequoia 15.8.2

The assumption at the boundary

The boundary I wanted to test was simple: being able to contact a system service should not give an app authority to control an existing VPN connection.

PPPController exposed two routes into that decision. One was the UNIX socket at /private/var/run/pppconfd. The other was the Mach service com.apple.SystemConfiguration.PPPController, reachable through SCNetworkConnectionStart.

The socket path made the trust problem especially clear. The implementation obtained the peer’s credentials using getsockopt with LOCAL_PEERCRED, but the client-creation call used zero values for the identity fields instead. The identity was available at the boundary; it was not carried through the decision that followed. The runtime record later attributed a start request to (0) kernel_task rather than the application that sent it.

There was an important prerequisite: a configured PPP/L2TP service had to exist already. The service lookup rejected an unknown service. This was control over an existing connection, not evidence that an app could create arbitrary system VPN configurations.

From a sandboxed app to a privileged service

The first useful result was not just a successful socket connection. In the 26 August 2026 test on macOS Tahoe 26.6, build 25G72, the start request was accepted and a pppd process appeared under configd with UID 0.

The app was running with App Sandbox enforced. Its entitlement file included both com.apple.security.app-sandbox and com.apple.security.network.client. Controls in the record showed other local socket destinations denied, and a file write outside the container was blocked. Those checks matter: an unrestricted command-line process would not establish the same boundary crossing.

The captured response to the socket start request was:

RESPONSE: type=0x0003 result=0x00000000 cookie=0xdead9001 link=0x00050000

The process snapshot recorded the resulting service:

PID  PPID USER   UID   GID STAT COMMAND
12230   369 root     0     0 Ss   pppd serviceid B53A0B91-EF59-414B-8206-680F8E27ADC7 controlled

This established a concrete privileged effect: an app confined by App Sandbox could cause this system service to start. It did not establish arbitrary command execution as root. The process was Apple’s pppd, carrying out the connection workflow.

Blast radius: what we actually reached

The evidence spans different entry points and different runs. Treating them as one uninterrupted exploit would hide the conditions under which each result occurred. The map below keeps those conditions attached to the result.

Evidence map / PPPController Observed outcomes

How far did it reach?

Follow each test to its last demonstrated effect.

26 AUG 2026 / macOS 26.6SOCKET PATH

A privileged service,
started.

  1. Sandboxed appApp Sandbox
    + network.client
  2. Legacy socketpppconfd
    Start accepted
  3. configdRequest attributed
    to kernel_task
  4. pppdUID 0
    Service launched

Reached: a privileged VPN service action from App Sandbox. Starting this daemon did not establish arbitrary root code execution.

26 AUG 2026 / macOS 26.6SEPARATE API TEST

A destination,
redirected.

  1. Local processOutside
    App Sandbox
  2. PPP optionsNew destination
    127.0.0.1
  3. L2TP serviceSupplied test
    credentials
  4. 54 packetsLoopback listener
    Control traffic

Reached: the chosen network destination. This capture did not demonstrate a completed tunnel or intercepted user traffic.

02 OCT 2026 / macOS 27.0.1STORED-ACCOUNT RETEST

The credential chain
stops here.

  1. Sandboxed appStored username
    Four attempts
  2. Start APIRequest accepted
    pppd started
  3. Keychain APILookup invocation
    Recorded in log
  4. 0 packetsNo dial
    No credential capture

Limit: credential handling was reached, but delivery was not. The receiver recorded no traffic in these four attempts.

Each view is a separate test. The observations are not combined into a single end-to-end exploit.

The practical reach was into an existing legacy VPN service: accepting a start request, launching its process, reaching credential-handling code, and — in a separate API test — changing where its L2TP connection attempt went.

For a machine that uses that service, these are consequential authority decisions. The affected resource is the configured VPN connection and its system-managed workflow. The tests do not establish control over every VPN product, all network traffic on the Mac, or other users’ keychain items.

Following the destination onto the wire

To test destination control, I set CommRemoteAddress to 127.0.0.1 and listened on the loopback interface. This kept the observation on my own machine. The API returned success, and the listener captured 54 L2TP control packets on 26 August.

These are selected lines from that capture. The process was outside App Sandbox for this run and supplied test credentials; that context stays with the result.

[15:37:18.487] sandbox_check = 0 (NOT SANDBOXED)
[15:37:18.493] SCNetworkConnectionStart returned: TRUE
[15:37:18.699] *** CAPTURED PACKET #1: 20 bytes from 127.0.0.1:60636 ***
[15:37:24.033] Total packets captured: 54

The first captured packet contained these bytes:

0000: c8 02 00 14 00 00 00 00 00 00 00 00 80 08 00 00
0010: 00 00 00 06

The receiver established that the connection attempt reached the chosen destination. These were control packets. They do not, by themselves, demonstrate a completed VPN tunnel, intercepted application traffic, or a password arriving at the listener.

Credential-theft path: System Keychain to PPP authentication

The credential path is the most consequential part of the report. The question was whether an app could choose a new VPN destination while the system supplied a credential belonging to an existing connection.

PPPController looked for a password in the caller’s options and then fell back to the stored service configuration. When that configuration selected Keychain-backed storage, the controller passed a keychainpassword reference into pppd. The destination and the credential could therefore come from different trust sources: the caller selected the address, while the existing service supplied the password reference.

The credential-theft path

The password’s route.

A code path, with its evidence attached.

  1. 01
    Choose a new VPN destination

    CommRemoteAddress → a listener under my control.

    Observed in a separate API test
  2. 02
    Reach stored-credential handling

    Existing service → Keychain lookup by pppd.

    API invocation observed
  3. 03
    Copy the returned password

    On lookup success → memmove → buffer 0x10004964c.

    Static binary trace
  4. 04
    Pass that buffer to PAP

    The same address → _upap_authwithpeer.

    Static binary trace
  5. 05
    Receive the credential at the endpoint

    Requires a completed tunnel and authentication exchange.

    Not captured

The first two observations came from the named test runs. The final delivery step was not demonstrated; the later stored-account retest stopped before dialling.

The binary trace connected the password-retrieval code to PPP authentication through the same buffer address, 0x10004964c. On a successful Keychain lookup, pppd copied the password into that buffer. Its PAP path later passed that buffer to _upap_authwithpeer. These addresses identify the historical binary analysed in the report; they are not universal offsets for other macOS builds.

Selected instructions from the archived disassembly:

100003efc:  bl   SecKeychainFindGenericPassword
100003f00:  cbz  w0, 0x100003e2c
100003e44:  add  x20, x20, #0x64c
100003e48:  mov  x0, x20
100003e4c:  bl   memmove

100001320:  add  x2, x2, #0x64c
100001328:  bl   _upap_authwithpeer

The runtime record reached the retrieval API too. This raw line belongs to the socket-path process:

2026-08-26 14:14:40.630 A  pppd[12230:152b068] (Security) SecKeychainFindGenericPassword

What was achieved: sandbox access to the connection-start operation and privileged daemon startup; a separate destination-override test delivered L2TP packets to my listener; runtime logs reached the credential API; and the binary trace linked a successful retrieval to the PAP password buffer.

What the archive does not establish: a stored password arriving at the receiver. A function invocation is not a dump of its returned bytes, and the captured L2TP control packets are not PPP authentication packets. The credential-delivery step was traced in code, not captured end to end on the wire.

If a hostile endpoint completed the required tunnel and negotiated PAP along that path, it could receive the VPN username and password. PAP supplies the password to its peer; that does not imply an IPsec pre-shared key is itself transmitted in plaintext. The recorded tests did not complete this credential-capture scenario.

The possible downstream blast radius would then depend on where that VPN credential is accepted and what additional authentication is enforced. VPN-user impersonation is a consequential risk; corporate-network access, lateral movement, and compromise of internal services were not demonstrated here.

What the later retest changed

On 2 October 2026, the test machine was running macOS 27.0.1, build 26A434. The later record reproduced sandbox access to both entry points, but it also made the limits more specific.

  1. The socket path still started a root pppd. The request was accepted and keychain API activity followed, but this attempt did not dial the listener.
  2. The API path was now measured inside App Sandbox. It returned success and launched pppd through nesessionmanager. That process had real UID 501 and saved UID 0. Calling every API-path instance a “root process” would lose that distinction.
  3. The stored-account attempts stopped before network delivery. Across four sandboxed attempts with the real stored username and an attacker-selected shared secret, the listener received zero packets. Keychain API activity was recorded, but there was no dial and no captured credential.
  4. A separate test with supplied credentials still dialled loopback. An unsandboxed run captured 55 control packets before the IPsec connection failed. Another variant with an invented username produced a visible VPN credential prompt; its responder failed before authentication completed.

Those results narrow the claim. They do not justify a silent credential-theft demonstration, and they do not establish a complete phishing chain. They also should not be read as a statement about today’s patched macOS releases: these are observations from the named historical builds, while Apple’s public advisory separately identifies its Sequoia fix.

Remediation: keep the caller and credential bound together

The architectural lesson is to bind a service action to the caller who requested it. On the socket path, that means preserving and checking the peer identity before starting or changing a connection. Equivalent actions through the Mach interface need an equivalent authorization decision.

Connection options need their own trust boundary too. A caller’s ability to reach an API should not silently grant permission to combine a new destination with credentials belonging to an existing system-managed service.

These are recommendations derived from the observed implementation. Apple’s advisory describes additional restrictions; this note does not claim to reconstruct Apple’s exact patch. Security content of macOS Sequoia 15.8.2

Affected setup, update, and researcher credit

For the path described here, a local application needs to run on a Mac with an existing configured PPP/L2TP service. The sandbox tests used the normal outgoing-network entitlement as well as App Sandbox. The results do not describe every VPN implementation.

Apple documents the fix in macOS Sequoia 15.8.2, released on 26 October 2026. Install the current security updates for your macOS release; the historical builds used in the research are not a recommendation to remain on them. Apple’s release advisory

CVE: CVE-2026-112542 · Apple component: ppp

Reported finding: Unauth PPPController interfaces in configd allow cred theft and traffic redirect from App Sandbox

That is the report title. The evidence distinctions above apply to its credential-theft wording.

Apple credits Gabriel ‘0xv1n’ Cardona, Mrunal Chawda, Kujtim Kryeziu (Sentry), and Tristan Madani (Talence Security). The public fix is documented in Apple’s macOS Sequoia 15.8.2 advisory.

This article draws on my original PPPController report, the archived packet and process records, and the later rogue-server retest. The central finding is the authority decision: an App Sandbox caller reached an existing VPN’s system-managed workflow. The credential path explains why that boundary matters, while the recorded outcomes define how far the demonstration reached.

Thanks for following the question.

Continue the conversation on X ↗