worse_query Escape
How forcequitOS/worse_query obtains sandbox extensions from containermanagerd on iOS 26.0–26.7.2 and iOS 27.0–27.3 Beta 1.
- Repo: forcequitOS/worse_query
- Stars: 587
- Mechanism: MCM class-7 symlink
- Flags: 0x8100000000

How worse_query works (and why bad_query was patched)
Published by Taj C (forcequitOS/worse_query, 587 stars, GPL-3.0) and documented in detail by murk-sus/kamui-escape and kolbicz/WQFiles, worse_query is a container-level sandbox escape targeting Apple’s containermanagerd (MobileContainerManager / MCM).
Its predecessor, bad_query, passed relative path traversal (../../../../../../../..) inside container_query_operation_set_part_domain on MCM class 13 (`SystemGroup`). In iOS 27.2, Apple patched bad_query in two places:
MCMXPCMessageQueryexplicitly rejects any query whosepartDomaincontains..(loggingRejecting query with invalid partDomain).MCMFileManager realPathForURL:ifChildOfURL:resolves symlinks and rejects targets outside the container whenpartDomainis non-empty.
The class-7 part-directory symlink primitive
Apple’s iOS 27.2 fix validated partDomain, but it did not validate the container’s part directory itself when partDomain is left empty:
- Inside the app’s own container (MCM class 2), iOS 27.2 sandbox rules block
rename()onLibrary/Caches,Library/Preferences,Documents, andtmpwithEPERM (errno 1). - However, inside an App Group container (MCM class 7), the part directory
<app group>/Library/Cachesremains writable and renameable by the app. worse_querybacks up<app group>/Library/Caches, replaces it with a symbolic link pointing to the target MCM container path, and sends an XPC query tocontainermanagerdwith:class = 7(App Group)group_identifiers = <app’s own signed App Group>part = 3(Library/Caches)partDomain = ""(empty string: bypassing the 27.2partDomainchecks)flags = 0x8100000000(return path + issue read/write sandbox extension type 3)
containermanagerdconstructs<app group>/Library/Caches, resolves the symlink to the target container, and issues a valid sandbox extension token for the resolved path.- The app calls
sandbox_extension_consume()to gain read/write access, then immediately removes the symlink and restores the originalLibrary/Cachesfolder.
| Escape Strategy | Origin | App Group Required? | Behavior Across iOS 26 & iOS 27 |
|---|---|---|---|
Strategy 1: Class 13 + partDomain traversal | Legacy bad_query | No | iOS 27.0 / 27.0.1 builds where .. in partDomain was not yet rejected. Patched in iOS 27.2. |
| Strategy 2: Class 7 part-directory symlink | Primary worse_query | Yes (Mandatory) | iOS 26.0–26.7.2 and iOS 27.0–27.3 Beta 1. Replaces <app group>/Library/Caches with a symlink and queries MCM class 7, part 3, empty partDomain. |
| Strategy 3: Class 13 direct MG query | Direct SystemGroup query | No | Returns the container path on some builds, but issues no sandbox token unless the caller already holds the system entitlement. |
Strategy 4: Class 12 geod + traversal | Daemon fallback | No | Older pre-27.2 builds only. |
Reachable MCM container paths
| Filesystem Path Pattern | MCM Class | OS Availability | Access Level | What Lives Inside |
|---|---|---|---|---|
/var/mobile/Containers/Data/Application/* | MCM Class 2 | iOS 26.0–26.7.2 & iOS 27.x | Read / Write (`mobile`) | Every installed user and system app’s Documents, Library, Caches, and tmp directories. |
/var/mobile/Containers/Shared/AppGroup/* | MCM Class 7 | iOS 26.0–26.7.2 & iOS 27.x | Read / Write (`mobile`) | Shared App Group containers used by apps and their extensions/widgets. |
/var/mobile/Containers/Data/PluginKitPlugin/* | MCM Class 4 | iOS 26.0–26.7.2 & iOS 27.x | Read / Write (`mobile`) | App extensions (Share extensions, widgets, notification service extensions). |
/var/mobile/Containers/Data/InternalDaemon/* | MCM Class 10 | iOS 26.0–26.7.2 & iOS 27.x | Read / Write (`mobile`) | User-level background daemons including lsd’s LaunchServices database container. |
/var/containers/Shared/SystemGroup/* | MCM Class 13 | iOS 27.x only | Read / Write (`mobile` caches) | Holds systemgroup.com.apple.mobilegestaltcache and Supervision configuration profiles. |
/var/containers/Data/System | MCM Class 12 | iOS 27.x only | Directory listing only | Contents inside System Data are owned by root and protected by POSIX DAC. |
Container enumeration: LaunchServices DB vs fsgetpath inode scan
Because iOS sandbox rules prevent listing the parent directories (such as /var/mobile/Containers/Data/Application) directly, tools need a way to discover each container’s UUID folder name:
fsgetpathbrute-force inode scan (used by KAMUI, Regitela’spathleak, and WQFiles v0.1–v0.7): Callsfsgetpath()across inode numbers on the data volume until container directories are found. On a heavily used device, the first scan can take several minutes (and up to an hour on iOS 26).- LaunchServices database lookup (introduced in WQFiles v0.8): WQFiles locates
lsd’s container among recent inodes within seconds, reads the system LaunchServices database directly, and extracts the exact container paths, bundle IDs, and localized names for all App Data, App Groups, and Extension Data without waiting for a full-volume inode scan.



Common questions
Can worse_query read or write root-owned files in /var or /System?
No. worse_query only causes containermanagerd to issue sandbox tokens for MCM containers, and standard POSIX permissions (DAC) still apply. Files owned by root inside /var/containers/Data/System cannot be modified by user mobile.
Why does WQFiles keep a Caches backup during token requests?
Because the class-7 technique temporarily swaps