On August 31, 2026, I reported two defects in /System/Library/CoreServices/ScopedBookmarkAgent, the agent that converts security scoped bookmarks into sandbox extensions. An app signed with com.apple.security.app-sandbox and com.apple.security.files.user-selected.read-only obtained a read extension for the whole boot volume from a bookmark it created for /, and then obtained a write extension for a file it had opened O_RDONLY.

The App Sandbox treats reading a path and converting a path into an extension as two different operations, and an app cannot perform the second one itself. That split is the reason the agent exists. It also means the agent is exercising a privilege on the app's behalf, and the question is whether it applies the same test the profile would have applied.

What I found

The profile decides which paths an app may turn into an extension. Calling sandbox_extension_issue_file from a bare sandboxed bundle attempts the operation rather than asking about policy, so the result is the policy:

/Applications            ISSUED   len=184  errno=0
/System                  ISSUED   len=178  errno=0
/Library/User Pictures   ISSUED   len=193  errno=0
/                        refused  len=0    errno=1
/Users                   refused  len=0    errno=1

The first three are positive controls and they correspond to real grants in application.sb: line 534 allows file-issue-extension on /Applications, line 364 on /System, and line 89 on /Library/User Pictures. The instrument fires. Both / and /Users are refused with EPERM.

The only rule in application.sb that grants extensions over (subpath "/") is line 77, and it is gated on com.apple.security.temporary-exception.yasb, which this app does not hold. Apple grants the app read of the root node and withholds the power to extend it. The agent performed that conversion anyway, for a bookmark the app created by naming / itself.

The entitlement the app does hold is described in Apple's Entitlement Key Reference as "A Boolean value that indicates whether the app may have read-only access to files the user has selected using an Open or Save dialog." Nothing was selected here. There was no dialog and no user action.

The second defect is in the same agent, on the path that decides what class of extension a bookmark resolves to. security_policy_permits_url branches on whether the request is app scoped, and the app scoped branch tests only NSURLIsRegularFileKey or NSURLIsDirectoryKey. The read-only downgrade is the comparison that routes a regular file away from the write check:

0x100007f3c    cmp   w22, #0x4, lsl #12
               b.ne  0x100007fb8

A regular file with an O_RDONLY descriptor reaches the same continuation as one opened O_RDWR. The directory branch three instructions later calls sandbox_check_by_audit_token(peer, "file-write-data"), which is the only sandbox operation string in the binary. The regular file case never reaches it, and at resolve the extension class is taken from options carried inside the bookmark.

Both halves in one run, from a signed bundle holding nothing beyond the two entitlements named above:

poc974
  before   /Users     policy=denied    opendir=DENIED errno=1
  before   canary     = DENIED
  bookmark = 460 bytes
  after    /Users     policy=PERMITTED opendir=OK (6 entries)
  after    canary     = CANARY-e32971965938
  revoked  /Users     policy=denied    opendir=DENIED errno=1

poc975
  before     read=denied    write=denied
  read-ext   read=PERMITTED write=denied
  fd=4 accmode=0
  after      read=PERMITTED write=PERMITTED
  write() appended 36 bytes

The descriptor is read only on both sides of that change. F_GETFL reports accmode 0, fstat reports S_IFREG, and a write() through it returns EBADF before the bookmark is resolved. A directory with the same options is downgraded correctly, which is what pins the defect to the regular file branch rather than to the bookmark format.

The volume extension itself is read only. It denies write, create and unlink, and open(O_CREAT|O_EXCL) on a new path is refused, so the write is per file and needs a file that already exists. The baseline matters here as well: a bare sandboxed bundle already reads /Library, which line 80 allows outright, and is refused on /Users, /private, the user's home, ~/Library and ~/.ssh. Those refusals are the ones the minted extension converted to reads, and all of them returned on stopAccessing.

The impact is that a sandboxed app reads any file the user can read outside Documents, Desktop and Downloads, which prompt, and modifies any existing file the user can write. There is no prompt and nothing is declared. That matters most on the Mac App Store, where the sandbox is mandatory and is the boundary a user is relying on, and where both entitlements are ordinary enough to draw no attention in review.

Report status

I reported this under OE11073209914418. Apple credited me in the File Bookmark entry for CVE-2026-43785, published on September 14, 2026 in iOS 27 and iPadOS 27, macOS Golden Gate 27, macOS Sequoia 15.8, macOS Tahoe 26.7, tvOS 27 and visionOS 27. Apple states the impact as "An app may be able to modify a file it only had permission to read" and describes the fix as a permissions issue addressed with additional restrictions.

I re-tested on macOS 27.0 (26A428) after the update shipped. Neither half reproduces. The agent refuses and returns its own error instead of a bookmark, and the probes in that same run still fired on their positive controls, so the refusals are the fix rather than an instrument that stopped working.

An app that is denied a capability by its sandbox profile is only denied it for as long as every daemon willing to exercise that capability on the app's behalf applies the same test.