Why Design Survives Reimplementation
In OpenHarmony, the most revealing security question is not whether an inter-app message works, but whether the system can tell which component is entitled to receive it. This chapter follows that question through Android's Intent model and OpenHarmony's analogous Want mechanism. The goal is to make endpoint hijacking understandable as a chain of design decisions—what the caller asks for, how the operating system resolves the request, and what happens when the resolver trusts the wrong identity.
That chain explains why a new implementation can reproduce an old vulnerability. The relevant object that crosses the boundary is not source code. It is a request whose meaning the operating system must interpret.
A receiver chosen by behavior, not identity
An inter-component communication system has to solve a practical problem. One application wants another component to perform an action: open a screen, handle a piece of data, or start a system operation. The platform can require the caller to name one exact component, or it can let the caller describe the desired action and choose a receiver dynamically. The second option is more flexible. Applications can cooperate without knowing every component that may be installed later, and the operating system can select among components that advertise the same capability.
Android's implicit Intent is built around that second choice. An Intent carries an action rather than a fixed destination. The system compares the request with Intent filters registered by components and chooses a receiver. The design decouples the sender from the receiver, but it also changes the meaning of “the other application.” The sender has named a behavior, not a verified identity. If a malicious application can register a matching filter, it may be placed in the path of a request that the sender or user intended for a trusted component.
The security failure follows in a few steps:
- The caller creates a request for a sensitive action.
- The request does not identify one authorized receiver.
- The operating system searches for components that claim to handle the action.
- A malicious component presents a matching claim.
- The resolver treats that claim as sufficient and routes the request, data, or control to the wrong endpoint.
The resolver may be functioning exactly as designed. That is what makes this a design-level vulnerability. The dangerous rule is not “the resolver sometimes forgets to check a string.” It is “a matching advertisement is enough to establish authority over a sensitive action.” An implementation can be clean, deterministic, and well tested against its functional specification while still enforcing that unsafe rule.
The consequences depend on what the request carries. A malicious receiver may obtain information that the sender assumed would reach a trusted component. It may substitute a response, change the next action, or imitate a system surface. The same resolution decision can therefore threaten confidentiality or integrity. The problem is not confined to a single app: the operating system has made a cross-app trust decision on behalf of all participants.
OpenHarmony gives the comparison a concrete test. Its Want objects can express an action without specifying the target Ability—the OpenHarmony role analogous to an Android Activity. The paper reports a case in which an app can request the Settings application through an implicit Want, while a malicious app registers the same Settings action. The malicious component can then be launched instead. The authors report that critical system actions lack the protection needed to prevent this hijacking.
This parallel does not show that OpenHarmony copied Android's resolver code. The researchers' broader comparison found that the systems are independently implemented. It shows something narrower and more useful: both platforms expose a role in which an action can be resolved without binding it to a verified component. The shared security risk follows from that role and its trust assumption.
The sequence has two separate questions hidden inside it. First, is the caller allowed to request the action? Second, is the receiver entitled to handle it? A permission check on the caller can answer the first question without answering the second. Conversely, a receiver may be a legitimate handler for a low-risk action but not for a request containing credentials, private data, or control over a protected system function. Treating “can invoke” and “may receive” as one decision is how a flexible interface becomes an authority-confusion problem.
The same distinction applies to the data moving through the request. A component may be allowed to announce that it handles an action, but that announcement does not prove that it should see every argument or result associated with the action. A safer design may require an explicit target, a verified origin, a permission on the receiving side, or a system-owned allowlist for critical actions. Those choices reduce flexibility, but they make the trust relationship visible instead of leaving it to the resolver's broadest interpretation.
A useful way to analyze the design is to separate the caller, the resolver, and the endpoint. The caller owns the decision to ask for an operation. The resolver owns the decision about where the request goes. The endpoint owns whatever state the operation reads or changes. A vulnerability appears when one of those responsibilities is silently treated as another. For example, the resolver may assume that the caller's permission also authorizes the receiver, or the receiver may assume that the resolver already checked the request's origin. Each component can then behave correctly according to its local assumption while the combined system grants authority that no component explicitly accepted responsibility for.
The danger does not require an obviously hostile request. A normal application can send a valid action, and the malicious component can provide a valid-looking response. That makes endpoint confusion different from malformed-input handling. The input may be well formed; the failure is that the platform interprets a legitimate-looking message in a context where the recipient's identity matters. A successful functional test can even reinforce the false confidence: some component handled the action and the caller received a result. Only a security test that asks whether the intended component, rather than merely an eligible one, handled it can expose the difference.
Ownership of state makes the distinction sharper. If an action opens a public screen, a broad receiver may create inconvenience or confusion. If the same action carries a credential, a private record, or a command to a privileged service, the receiver becomes part of the confidentiality and integrity boundary. The resolver must either preserve that sensitivity through the handoff or refuse the request when it cannot establish the necessary trust. Otherwise, the platform has turned a capability advertisement into access to data or control that the advertising component was never meant to hold.
The boundary also has a lifecycle. At creation, the system decides which identities and permissions are attached to a request. During resolution, it decides whether those identities remain meaningful. While the endpoint runs, it may create callbacks, return data, or trigger another component. At termination, the system must not leave behind a token or shared state that a different component can reuse. A design review that looks only at the first call can miss a later transition where the same trust assumption is reopened. The paper's broader DLV catalogue contains such failures in IPC, broadcasts, data sharing, and other cross-component mechanisms; the common issue is that the boundary changes as the request moves.
That is why “make the target explicit” is a useful mitigation idea but not a universal answer. An explicit target can reduce ambiguity, yet the target may still be exported too broadly, accept an unverified caller, or receive more data than it needs. Conversely, dynamic discovery can remain safe for low-risk functions if the platform authenticates the origin, limits the data, and reserves sensitive actions for trusted handlers. The design objective is not to eliminate composition. It is to ensure that composition does not become an unexamined transfer of authority.
The five questions every boundary must answer
The Want example is valuable because it turns an abstract security principle into a sequence. It also gives us a general test for OpenHarmony and other emerging operating systems. Whenever a platform lets one component invoke another, the audit should ask five questions.
Who may invoke? The first question concerns the caller's authority. Is the operation open to every application, limited by a permission, restricted to a privilege level, or dependent on user consent? OpenHarmony's permission documentation describes normal, system_basic, and system_core application privilege levels, along with system_grant and user_grant permissions. Those concepts express intended authority boundaries. They do not, by themselves, show that every alternate route to the same operation enforces the same boundary.
Who may receive? The second question is about the endpoint. Does the caller identify a particular component, or does the operating system choose among all components that claim a capability? If it chooses, what prevents a newly installed component from making a false or overly broad claim? The implicit Want result shows why endpoint authorization is not a decorative refinement. The receiver is part of the security decision.
What origin is verified? A request can arrive through a legitimate channel and still come from the wrong principal. Origin validation asks whether the system has evidence that the request came from the app or component that the receiving side should trust. The paper's other Android DLVs show the same question in broadcasts, data-sharing components, and system IPC. These mechanisms differ, but they share the problem of treating an apparent source or endpoint as trusted without sufficient verification.
What state or data crosses the boundary? Not every action has the same sensitivity. A public request to display a screen is different from one that carries a token, private record, or permission-bearing result. The system should know what the endpoint can observe and modify, not just whether it can accept the action name. This is why the paper treats unprotected broadcasts, data-sharing components, and system IPC as related design problems. A channel can be available while the information or control it carries is not.
What happens by default? Security failures often appear when a field is omitted, a permission is not declared, a user is absent, or no exact endpoint is named. A design that fails closed makes the exceptional case safer. A design that resolves to any matching component, exposes a fallback interface, or accepts a missing authorization may turn convenience into the normal path. The default is not a minor implementation detail; it is the behavior most applications will rely on.
These questions also explain why similar names are not enough to prove a transferred vulnerability. “Want” is not automatically an insecure Intent. The relevant evidence is a chain: OpenHarmony has an analogous action-resolution capability; the capability makes the same kind of trust decision; and a test shows that an unauthorized component can actually intercept or redirect a sensitive request. If any link is absent, the proper conclusion may be that the historical DLV is inapplicable or that the available evidence is incomplete.
Ordinary implementation testing can miss this chain because it often checks whether the selected component performs the expected operation, not whether the selection itself was authorized. A static analyzer may find that a function handles a request but not whether the system should have admitted a second handler. Fuzzing may exercise many inputs while preserving the same unsafe rule for every valid input. A design-level audit instead treats the security invariant as the test subject: only the intended endpoint should receive this class of request, and a component's claim to handle an action should not be enough when the action is sensitive.
That audit is not a rejection of implementation testing. The resolver still needs tests for parsing, races, crashes, malformed messages, and incorrect state transitions. Those tests answer whether the implementation matches its design. A DLV review asks the prior question of whether the design should be implemented that way at all. The two forms of assurance catch different failures and must be connected rather than substituted for one another.
There is a real engineering trade-off here. Dynamic discovery makes an ecosystem extensible and reduces hard-coded dependencies. Strict allowlists and explicit targets make security reasoning easier but may increase coordination and maintenance work when components change. The correct lesson is not that every cross-app interface must become rigid. It is that flexibility should not silently decide authority. For sensitive actions, the platform needs a mechanism that preserves extensibility while binding the origin, recipient, and permitted data to an explicit trust policy.
This is the point at which an analogy becomes a research claim. An engineer can look at Android's implicit Intent problem and suspect that OpenHarmony's Want mechanism is exposed to the same class of failure. But suspicion is not evidence. The researchers therefore needed a systematic way to identify which historical design flaws were relevant, map them to OpenHarmony's own components, and test the resulting boundaries. The next step is to examine how that portable audit was built from the Android security literature.