← All issues

[4] macOS sandbox profile symlink traversal

Severity: High | Component: WebKit auxiliary process sandbox initialization (macOS) | 69a8331

Rated High because the observable effect is sandbox profile substitution via symlink traversal, compounded by the datavault integrity check being compiled out on non-internal builds — the /.nofollow prefix and USE(APPLE_INTERNAL_SDK) ungating are directly visible in the diff with confidence 0.92.

WebKit processes could use an incorrect sandbox profile by following symlinks in the profile path. The fix prepends /.nofollow to the sandbox profile directory path and removes the #if USE(APPLE_INTERNAL_SDK) gate on the datavault integrity check.

Source/WebKit/Shared/mac/AuxiliaryProcessMac.mm

static String sandboxDirectory(WTF::AuxiliaryProcessType processType, const String& parentDirectory)
{
StringBuilder directory;
+ directory.append("/.nofollow"_s);
directory.append(parentDirectory);
switch (processType) {
...
static bool tryApplyCachedSandbox(const SandboxInfo& info)
{
-#if USE(APPLE_INTERNAL_SDK)
CString directoryPath = FileSystem::fileSystemRepresentation(info.directoryPath);
if (directoryPath.isNull())
return false;
if (rootless_check_datavault_flag(directoryPath.data(), processStorageClass(info.processType)))
return false;
-#endif
 
auto contents = fileContents(info.filePath);
if (!contents || contents->isEmpty())

Three changes: (1) sandboxDirectory() now prepends /.nofollow to the sandbox profile directory path, instructing the macOS kernel to reject symlink resolution for the given path. (2) processStorageClass(), which returns the datavault storage class string, is no longer gated behind #if USE(APPLE_INTERNAL_SDK). (3) The rootless_check_datavault_flag() integrity check in tryApplyCachedSandbox() is similarly ungated, ensuring datavault validation runs on all builds.

Symlink-following TOCTOU in sandbox profile path resolution, combined with missing datavault integrity validation on non-internal builds.

On macOS, WebKit auxiliary processes (WebContent, GPU, Networking) apply sandbox profiles at launch. These profiles are compiled and cached on disk in a datavault-protected directory. The /.nofollow path prefix is a macOS kernel mechanism that instructs the filesystem layer to reject symlink resolution for the given path — any symlink encountered during traversal causes the operation to fail rather than follow the link. Datavaults are a macOS SIP-related mechanism where directories are tagged with a storage class, and only processes with the matching com.apple.rootless.storage.<class> entitlement can write to them. rootless_check_datavault_flag() validates that a directory belongs to the expected storage class.

Before the fix, WebKit auxiliary processes resolved their cached sandbox profile directory paths without preventing symlink traversal. An attacker who could place a symlink in the path leading to the sandbox profile directory could redirect the process to load a different sandbox profile — potentially a weaker or attacker-crafted one. Additionally, the datavault integrity check that validates the sandbox cache directory was gated behind #if USE(APPLE_INTERNAL_SDK), meaning non-internal (production) builds skipped this validation entirely and would accept any cached sandbox profile without verifying datavault ownership.

🔒

Explores the layered failure in sandbox profile validation and the implications of security checks that only exist in development builds

Subscribe to read more

🔒

Multiple audit patterns identified for finding similar sandbox initialization gaps across WebKit platform code

Subscribe to read more