The Code That Never Runs Can Still Break the Phone

A signed mobile app is supposed to be reassuring: its package has an authenticated origin, its code runs inside a sandbox, and sensitive actions require permissions. PHANTOM, a study of Android and iOS availability failures, asks a more precise question: what can the operating system do with an app’s metadata before the app’s code is allowed to run? This series follows that question from installation through boot so readers can distinguish package authenticity from safe resource consumption—and understand why a declarative field can become a system-level hazard.

The familiar security story stops too early

Most explanations of mobile security begin when an application launches. At that point, the operating system can constrain what the process may read, which services it may call, and which user permissions it has received. Code signing helps establish that the package has not been altered after signing. Sandboxing limits the damage an already-running process can directly cause.

Those controls matter, but they are not one continuous wall. They guard different transitions in the application lifecycle. A signature answers an identity and integrity question: is this the package that its signer produced? A sandbox answers a runtime authority question: what may this process do after it starts? Neither question necessarily answers whether privileged installation services can safely parse every value embedded in the package.

That gap is the subject of PHANTOM, short for “Package-based Harmful Attack via No-code Triggered OS Malfunction.” The study describes a class of attacks in which the payload is not a program that executes on the phone. It is malformed or oversized installation metadata: the declarations that describe an application to the operating system. If a privileged service accepts such a value, stores it, or sends it to another service without adequate bounds, the failure can occur while the application is still only a package being installed—or later, when the system re-reads its stored metadata.

This changes the usual picture of a malicious app. The app may never display a screen, request a runtime permission, or perform a suspicious action. The operating system can still be harmed by work it performs on the app’s behalf. PHANTOM is therefore primarily an availability study. Its reported consequences range from a single feature becoming unstable to persistent boot failures that require a factory reset or a device restore, with associated data loss. It is not a claim that every signed app can execute arbitrary code before launch.

The distinction is important because “signed” and “safe” describe different properties. A package can be authentic while containing a value whose size, repetition, or downstream expansion exceeds an assumption made by a system component. The signature may successfully verify the package; the later parser may still fail when it turns the package’s declarations into system objects, serialized messages, or persistent state.

What is being trusted before code runs

The relevant files are ordinary parts of mobile software. Android requires an AndroidManifest.xml. It tells build tools, the operating system, and Google Play about application components such as activities and services, requested permissions, intent-facing capabilities, and device requirements. Many of its values are attributes, and normal manifests can contain repeated elements and references to resources. These are not incidental notes for developers. They are inputs the platform uses to decide what an application is and how other system components should interact with it.

Apple’s Info.plist plays an analogous role for a bundle. Apple describes it as a resource containing key-value pairs that identify and configure an executable bundle. Some keys describe the bundle itself; others control features, execution, protected resources, or services. An iOS application may also contain extensions—such as widgets or share features—with their own property lists. Each additional bundle gives the system more metadata to interpret.

The security significance comes from who reads these declarations and when. On Android, Package Manager Service parses the manifest during installation, saves extracted information as package state, and then triggers system activity that queries that state. Launcher, SystemUI, and other services may request package information, causing the stored metadata to cross process boundaries. On iOS, installation services and system interfaces parse and index bundle metadata before the application is allowed to execute. A Widget Extension can be scanned again by a system daemon during boot, even if the user has never placed that widget on a screen.

Consider what this means for a value that looks small and local in the package. A label, name, permission, or component declaration may be read once during installation, stored in a package database, copied into a framework object, and later included in a response to a system query. The value has not become executable code, but it has acquired several consumers. A repeated declaration can create a similar effect through accumulation: each entry may look ordinary while the complete response grows beyond what a receiving service can handle. A resource reference can postpone the real size of the value until a later stage when the system resolves it. The important question is not only “is this field syntactically valid?” but also “how much work and data does every later consumer inherit from it?”

This is why the word configuration can be misleading. In a narrow application-level sense, configuration is passive information. In a mobile operating system, package metadata helps construct a shared description of installed software. It can influence what appears in the launcher, which components are discoverable, how permissions are represented, and what other services learn when they enumerate applications. A failure in that shared description can affect a service that never belongs to the package and never grants the package a runtime capability. The system is doing the work, but the package supplies the input that shapes the work.

The difference from a conventional runtime attack is temporal as well as architectural. A runtime attack needs a process to start and reach a vulnerable operation. PHANTOM’s relevant paths begin earlier: installation services parse the declarations as part of accepting the package, and later system components may consume the resulting state automatically. On iOS, the reported Widget path adds another automatic transition at boot. A user does not need to open the widget for the boot-time consumer to encounter its metadata. On Android, post-install enumeration can happen as the system refreshes its view of installed applications. These automatic consumers are the reason “the app never ran” does not settle the availability question.

So the operating system is not merely opening a file on behalf of an app. It is accepting an external description and turning it into shared state. That state can be copied into objects owned by privileged services, serialized for inter-process communication, or consumed during recovery and startup. At each step, the original value may be farther from the package boundary and closer to an assumption that it is trustworthy configuration.

This is the lifecycle trust-boundary mistake at the center of PHANTOM: metadata supplied by an untrusted package is treated as if it had already been bounded by a trustworthy producer. The source is not necessarily trusted just because the package is signed. A certificate can establish who signed the bytes; it does not, by itself, prove that every consumer will handle the bytes within safe limits. A safer design must carry the opposite assumption forward: every service that parses, stores, serializes, or reuses package metadata must treat it as external input and enforce limits appropriate to its own representation.

flowchart LR A["Signed package arrives"] --> B["Privileged services parse\nmanifest or Info.plist"] B --> C["Metadata becomes stored\nor serialized system state"] C --> D["Availability failure\nbefore code runs"] A --> E["Application code executes later"] E --> F["Runtime permissions\nand app behavior"]

The ordering also explains why a later reboot can matter. If the problematic metadata remains part of the installed package or the system’s package state, restarting the phone does not necessarily remove the cause. A service may encounter the same value during the next boot and fail again. The initial installation and the later recovery cycle are not separate accidents; they are two readings of the same static input at different lifecycle stages.

The question PHANTOM makes unavoidable

The study evaluated 979 configuration fields across Android and iOS and reported 65 exploitable vectors: 33 on Android and 32 on iOS. It classified 25 as capable of complete system failure with persistent boot-loop consequences in the tested paths. Those figures describe the study’s corpus and classification rules, not the percentage of all mobile metadata that is dangerous. Their value is diagnostic: they show that the issue is not one curious field or one isolated crash, but a family of failures organized around where metadata is accepted, propagated, and finally materialized.

The two platforms do not fail in the same way. Android’s important paths involve package information, inter-process messages, and persistence encoding. iOS’s reported paths involve daemon memory limits and, for Widget Extensions, early-boot supervision. The shared lesson is not that Android and iOS use the same implementation. It is that both can place a high-consequence parser on the far side of a trust boundary without carrying forward enough limits and recovery isolation.

The study also keeps reachability separate from technical exploitability. An Android sideload still requires a user to approve installation. The iOS proximity scenario depends on an installable enterprise-signed IPA and user acceptance; AirDrop is not presented as an arbitrary-file or zero-click bypass. The researchers did not test whether malformed packages would pass official Google Play or App Store review. Those qualifications are part of the result, not footnotes to be discarded.

The practical judgment supported by this series is therefore narrower and stronger than “mobile apps are unsafe.” Code signing remains useful. Sandboxing remains useful. Store review can add another layer of screening. But none of those controls replaces a platform parser that bounds values, limits aggregate work, contains per-package failures, and preserves a safe route back to a usable system. To understand why, the next step is to look closely at what an app carries into the operating system—and why those declarations have more authority than their file-like appearance suggests.

References