> For the complete documentation index, see [llms.txt](https://docs.talsec.app/appsec-articles/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.talsec.app/appsec-articles/articles/breaking-the-android-sandbox-and-how-to-defend-against-it.md).

# Breaking the Android Sandbox and How to Defend Against It

In this blog, we will be analyzing **CVE-2024-0044**, a critical `run-as any app` vulnerability that sent shockwaves through the Android security community.&#x20;

Marked as **High Severity** by Google, this bug allowed attackers to bypass the fundamental Application Sandbox on Android 12, 13 and 14 using a surprisingly simple **command injection** technique and access any app's internal files `without even rooting the device`.

<figure><img src="/files/IH1zQmKJHp0VEQfkM12h" alt=""><figcaption></figcaption></figure>

We will observe how a tiny validation error in the Android Framework allowed anyone with ADB access (Remote or Physical) to trick the system into thinking any production app was debuggable. We will explore what this meant for millions of user devices **where private data suddenly became public property for anyone with a USB cable**.

Finally, we will look beyond the OS patch. We will demonstrate how **Runtime Application Self-Protection (RASP)** technologies, like [**Talsec freeRASP**](https://www.talsec.app/freerasp-in-app-protection-security-talsec), could have prevented this exploit from succeeding even on non-rooted unpatched devices by detecting the anomaly the moment the attacker tried to break in.

## How Android Apps Run

Android applications run in one of two build states:

* **Debuggable**
* **Production**

**Debuggable** state is designed for developers. It grants deep access to the app's data and internal files. However, this can be dangerous in the hands of an attacker, as it exposes the configuration files that control the app's behavior.

**Production** state is for apps distributed publicly. These builds are not debuggable, ensuring that private internal files are protected (at least on non-rooted devices). We simply need to set `android:debuggable="false"` in the manifest file to secure our authentication tokens and databases.

**This distinction was considered a hard security boundary. CVE-2024-0044 broke it.**

## Package installation

Another important thing to understand is how the package manager installation process works so the OS creates a record of the installed package.&#x20;

The Android OS maintains multiple registries and `XML` files containing configuration for processes on the device. One of these files is `packages.list` - registry that stores info about installed packages. Since it resides in the privileged `/data/system/` directory, it can only be written to by the [Package Manager](https://developer.android.com/reference/android/content/pm/PackageManager).

It stores the configuration of each app on the device in this format:

```xml
<package_name> <uid> <debug_flag> <data_dir> <seinfo> <installer_package_name>
```

The Package Manager writes these lines through [`Settings.writePackageListLPr`](https://android.googlesource.com/platform/frameworks/base/+/3e7d977/services/core/java/com/android/server/pm/Settings.java#2181) by concatenating the fields. This straightforward appending of fields turned out to be a massive vulnerability in the context of this bug.

<figure><img src="/files/bEl3mHXAdkgSfDHL4125" alt="" width="480"><figcaption></figcaption></figure>

### The `run-as` binary

To understand the exploit, we need to look into the tool it tricks the `run-as` binary. This is an Android command-line tool that is designed specifically for debuggable apps of the device that acts as superuser of data of the debuggable apps.

#### **What does it actually do ?**

The run-as tool allows a user to execute commands as a target application.

* It grants read/write access to the data directories of the target app.
* It also grants the shell user ability to impersonate the target application's UID's user.

**Due to these privileges provided by this tool , it is only allowed to work for debuggable apps**.

#### **Parsing**

To know if the app is debuggable or not, the run-as binary checks the `debuggable_flag` field of the `packages.list` file and totally relies on that for this validation.It also parses the `Data Directory` and `UID` fields from the `packages.list` file to call `setuid` and `setgid` without further verification

#### How it decides

To decide whether an app is debuggable, `run-as` checks the `debuggable_flag` field in `packages.list` and fully trusts it. It also parses the `Data Directory` and `UID` fields from that file and uses them in `setuid` and `setgid` calls without further validation.

## CVE-2024-0044

### How it worked

The vulnerable code can be traced to commit `I840c9c9af5752b3901d4719a13e7908faa43ab04`.

<figure><img src="/files/1l4LEZafj5MwfbOyyzll" alt=""><figcaption></figcaption></figure>

Here the first half of the vulnerability lies in the part where there is no verification apart from the length and null checking of the packageName. Also ADB is allowed to override the installing Package Name of the package installed giving the attacker ability to inject the payload using the `-i` flag.

The `-i` flag in the command `pm install ....` allows the user to set the installing Package name of a package. By default, it is `com.android.vending` that refers to the Google PlayStore. This is written as the last field of the configurations inside the `packages.list` file discussed before .

The second half of the vulnerability lies inside the `run-as` tool parsing that does not parse using any XML parser but parses the file line by line thinking every newline means configuration a new app. A person can simply inject a carefully crafted malicious payload to change the configurations of an application inside the device.

### Proof of Concept

For the POC, we are using a physical Xiaomi Redmi Note 11 5G device with Android 13 which is affected by this vulnerability.

* In the POC video, we can observe that on a normal `adb shell` we are not allowed to iterate into the private directories of non-debuggable apps like the `production grade Google Chrome` app and the `run-as` tool denies that the app is non-debuggable.
* Then we run `exploit` binary on the local system attached using wireless debugger with the Android phone.
* Using the injection vulnerability inside the Package Manager's `package.list` file and the lack of validation checks allows us to change the contents of this file according to our desire.

{% embed url="<https://youtu.be/sr-FCF23oXE>" %}

* In a normal `adb shell`, we cannot enter the private directory of a non-debuggable app such as **Google Chrome**.
* The `run-as` tool correctly denies access because the app is not debuggable.
* Next, we run the local `exploit` binary while connected to the phone through wireless debugging.
* The payload abuses the Package Manager write path and rewrites `packages.list` with attacker-controlled data.
* After that, `run-as` parses the malicious entry and treats Chrome as debuggable.
* Because the payload injects a fake alias and fake directory path, we can use `run-as <fake_name>` to enter the target app’s private directory.
* This makes non-debuggable apps accessible even on non-rooted devices.
* The demo also uses `tar -cf` streaming to copy data into `/data/local/tmp`, where it can be pulled through a normal ADB shell.

#### Exploit development

The exploit POC for the vulnerability contains mostly helper functions which run `ADB` shell commands to let the attacker choose any package from the available devices and prepare the exploit payload for that specific package.

<figure><img src="/files/7K00qNvfBgnDOs0kgjSP" alt=""><figcaption></figcaption></figure>

The main payload looks like this:

```
std::string payload = "adb -s " + serial_chosen_device + " shell <<EOF\npm install -i \"@null\nattacker " + target_app_uid + " 1 /data/user/0/" + chosen_package + " default:targetSdkVersion=28 none 0 0 1 @null\" /data/local/tmp/dummy.apk";
```

Here is what it does:

1. It opens an `adb shell` session.
2. It uses a crafted `pm install -i` value with an injected newline.
3. It inserts the target app’s private directory and UID into a forged entry.

That produces content like this inside `packages.list`:

```
dummy.apk ......... @null
attacker target_app_uid 1 /data/user/0/target_package default:targetSdkVersion=28 none 0 0 1 @null /data/local/tmp/dummy.apk
```

Once that entry exists, `run-as` grants privileges based on the forged record.

#### Mitigation Patch

Google mitigated this vulnerability by adding some more verification in the function responsible for package installation using ADB pm command. It not just checked the length of the installer package name but also validated the name using a separate function.

<figure><img src="/files/qphIXNVhPbgoWnxILxxM" alt=""><figcaption></figcaption></figure>

This new function restricted the `use of digits and underscores` as the first character of the package name. Also it banned use of special characters like `\n` in the name causing our malicious payload for this vulnerability to fail.

<figure><img src="/files/VOIBkiMCTiwrzPC6GlFt" alt=""><figcaption></figcaption></figure>

This update in the Android OS code was distributed on millions of devices soon to prevent any severe effects of this exploit in any device globally. But what if the attacker himself owns the device ? He will not update the device and then easily can have a privileged shell inside a non-rooted device.

#### Impact on Production Apps

The most alarming aspect of **CVE-2024-0044** wasn't just that it existed, but where it struck - the production grade apps. For years, the security model of Android relied on a simple rule: **"If the app is not debuggable, its data is safe on a non-rooted device."** This vulnerability shattered that assumption.&#x20;

By tricking the OS into treating a production app as debuggable, attackers gained the same level of access as the developers of the application. This meant the **Application Sandbox** which is the primary wall separating one app's data from another effectively vanished and the security rule of the Android OS broke.

#### Banking and fintech impact

The impact was catastrophic as financial apps rely heavily on the sandbox to protect local storage. With `run-as` access, an attacker could:

* **Bypass biometrics:** Modify local configuration files to disable client-side checks or flags.
* **Cookie stealing**: Standard Android sandboxing makes this folder impossible to read. With `run-as`, the attacker can simply copy the `Cookies` database file and steal important webviews data of the application.

#### Gaming and digital goods impact

Mobile games often store game state locally to ensure easier offline experience.

* **Economy Exploits:** Attackers could easily modify local XML files to give themselves unlimited currency or premium items and other advantages regarding in-app purchases.
* **Save File Tampering:** Competitive integrity was compromised as users could edit their stats or inventory directly in the file system without needing a rooted device.

## Why conventional defenses failed

Security teams often rely on a standard checklist of defenses: Root Detection, Signature Verification, and Anti-Tampering. **None of these worked against CVE-2024-0044.**

* **Root Detection was Useless:** The device was **not rooted**. The attacker was using a legitimate feature of the Android OS (`run-as`) that was simply misbehaving. Since the `su` binary wasn't present and the system partition wasn't modified, standard root detection libraries inside most of the prominent fintech and banking apps saw nothing wrong.
* **Tamper Detection Failed:** The attack did not modify the APK file or tampered with any of its memory region. The application signature remained valid, and the checksums matched. The integrity of the `installer` was compromised, not the `app package` itself.&#x20;

This is where the necessity of active self-protection arises instead of just passive checking. We need a security layer that detects the anomalies inside the application in real-time and check the memory of the application in runtime, regardless of what is described by the OS. This brings us to **Runtime Application Self-Protection**.

### How RASP helps

RASP technology operates independently of the Operating System, they do not rely on the corrupted `packages.list` file or system permissions. Instead, they actively monitor the application's runtime memory for the specific **signatures of an attack** such as a **debugger presence** or an active **ADB connection** in the device. Because the exploit requires these tools to function, RASP detects the intrusion instantly and terminates the app before the attacker can execute a single command, effectively neutralizing the threat for a production app even on a vulnerable device.

#### Talsec freeRASP

Built around the idea of *Security for Everyone*, [**freeRASP**](https://github.com/talsec/Free-RASP-Community) provides a lightweight, community-driven layer against common Android attack vectors, including the ones used here: **debugging, ADB access, and dynamic instrumentation**.

Unlike basic root detection, freeRASP does not just ask the OS whether something is wrong. It actively monitors the app’s runtime memory and integrity.&#x20;

If an attacker attaches a debugger or uses a `run-as`-style path to interfere with the app, freeRASP can detect it independently of the OS view and react before private data is exposed.

<figure><img src="https://t9012551331.p.clickup-attachments.com/t9012551331/5d3eab76-bd48-41c1-897a-62456301651a/Pasted%20image%2020260228175107.png" alt=""><figcaption></figcaption></figure>

#### How to Prevent Debugging Using freeRASP

Integrating freeRASP to block the **CVE-2024-0044** attack path is straightforward. The SDK provides callbacks for events such as debugger attachment and active ADB access. That lets you crash the app, block the session, or wipe sensitive state as soon as the attack starts.

For implementation details, use the [freeRASP documentation](https://docs.talsec.app/freerasp).

<figure><img src="/files/ohwuuQaZytn6arw2PAjf" alt=""><figcaption></figcaption></figure>

## Conclusion

CVE-2024-0044 is a reminder that even well-established security boundaries can be undermined by a single missing validation. A newline character in an installer package name was all it took to corrupt Android’s app registry and hand an attacker developer-level access to any app on the device - no root required.

The OS patch from Google closes the specific injection vector. But it does not help users on unpatched devices, and it illustrates a broader point: passive defenses that ask the OS for the ground truth are only as reliable as the OS itself.

Runtime Application Self-Protection represents a different model - one that monitors what is actually happening inside the app at runtime, independent of whatever the system reports. Against an attack that works precisely by corrupting the system’s own records, that independence is the difference between detection and compromise.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.talsec.app/appsec-articles/articles/breaking-the-android-sandbox-and-how-to-defend-against-it.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
