MALintent: Coverage Guided Intent Fuzzing Framework for Android

Ammar Askar

Network and Distributed System Security (NDSS) Symposium 2025 · Day 1 · Android Security 1

Overview

The talk "MALintent: Coverage Guided Intent Fuzzing Framework for Android" by Ammar Askar introduces a novel approach to identifying critical vulnerabilities within Android applications by systematically fuzzing their inter-process communication (IPC) mechanisms, specifically Android Intents. Given Android's stringent app isolation model, where each application operates within its own Linux user context, the primary vector for interaction and potential attack between apps is through the operating system's IPC facilities. Intents, as the foundational element of Android's IPC, represent a significant and often overlooked attack surface, with a noticeable rise in associated CVEs.

Watch on YouTube · Slides

Key moments

  1. 0:00 Introduction to MALintent and IPC attack vectors
  2. 1:00 What are Android Intents and their structure?
  3. 2:30 Generating intent specifications from app manifest and code
  4. 4:00 MALintent's fuzzing loop and bug detection oracles
  5. 4:40 Optimizing native code fuzzing using JNI data flows
  6. 6:00 Example: Memory safety bug in Facebook's image library
  7. 6:30 Detecting and exploiting privacy violations with intents

MALintent: Coverage Guided Intent Fuzzing Framework for Android

Speakers: Ammar Askar

Conference: NDSS Symposium

YouTube: https://www.youtube.com/watch?v=zXgS7Vb8E7w

Overview

The talk "MALintent: Coverage Guided Intent Fuzzing Framework for Android" by Ammar Askar introduces a novel approach to identifying critical vulnerabilities within Android applications by systematically fuzzing their inter-process communication (IPC) mechanisms, specifically Android Intents. Given Android's stringent app isolation model, where each application operates within its own Linux user context, the primary vector for interaction and potential attack between apps is through the operating system's IPC facilities. Intents, as the foundational element of Android's IPC, represent a significant and often overlooked attack surface, with a noticeable rise in associated CVEs.

MALintent addresses this critical security gap by providing a coverage-guided fuzzing framework tailored for Android Intents. The framework's significance lies in its ability to automatically discover a range of severe vulnerabilities, including privacy violations, memory safety issues in native code, and application crashes. Through a multi-pronged approach encompassing static analysis of app manifests, dynamic code instrumentation, and sophisticated bug oracles, MALintent demonstrates the pervasive nature of intent-related flaws in even widely-used, mature applications like Chrome, WhatsApp, and Instagram. This work is crucial for both security researchers and Android developers, highlighting the need for more robust intent handling and validation practices across the ecosystem.

Background

▶ Watch: Introduction to MALintent and IPC attack vectors (0:00)

Android's security architecture is fundamentally built upon a strong application isolation model. Each installed application runs as a distinct Linux user ID, effectively sandboxing it from other applications and the core system. This isolation prevents direct memory access or arbitrary file system manipulation between apps. Consequently, for applications to interact or share data, they must rely on the operating system's defined Inter-Process Communication (IPC) mechanisms. Among these, Intents are the most prevalent and versatile.

An Intent is an abstract description of an operation to be performed. It serves multiple purposes:

  1. Launching Activities: Starting a new screen or component within an app or another app.
  2. Starting Services: Initiating background operations.
  3. Delivering Broadcasts: Sending system-wide or app-specific notifications.

Intents are structured objects comprising an action (e.g., ACTION_SEND, ACTION_VIEW), data (a URI pointing to the data to be acted upon), a category (additional information about the kind of component that should handle the intent), and extras (key-value pairs for additional metadata). For instance, an app wanting to share a photo might create an intent with ACTION_SEND, specify the image URI in the data field, and include a subject line in the extras. The Android system then resolves this intent to an appropriate recipient app (e.g., a messaging app or email client), which then processes the intent.

While intents are designed for seamless app integration and user convenience (e.g., pre-filling an email address in a mail app), their cross-app boundary nature makes them a prime target for attackers. Developers often design internal intent handlers assuming trusted input, failing to account for potentially malicious intents originating from an attacker-controlled application. This oversight can lead to severe vulnerabilities. The talk highlights a concerning trend: the number of CVEs related to IPCs and intents has been steadily increasing, underscoring the growing importance of this attack vector. A compelling motivating example presented was a bug found in Chrome, where a malicious app could send an IPC to Chrome, causing it to leak sensitive data—including cookies, browser state, and a visual dump—onto the file system. This allowed the attacker to gain access to the user's entire browsing history and session data. Such examples underscore why intents, with their structured and manipulable nature, represent an ideal foundation for systematic security testing through fuzzing.

Key Findings

▶ Watch: Generating intent specifications from app manifest and code (2:30)

The MALintent framework employs a robust, three-step methodology to uncover vulnerabilities in Android applications:

  1. Intent Specification Gathering: MALintent first analyzes an application's APK to extract a comprehensive specification of all intents it can accept and the associated metadata. This involves both static analysis of the AndroidManifest.xml file, where intents are formally declared, and dynamic analysis of the app's code to understand how these intents are processed and what data they expect. The output is a JSON-like structure that serves as the blueprint for fuzzing.
  2. Coverage Instrumentation: To enable effective coverage-guided fuzzing, MALintent instruments the target application. This allows the framework to monitor code execution paths and identify new, unexplored branches as different intents are sent. While the talk briefly mentions a novel technique for Android coverage instrumentation using Java debugger APIs, the detailed technical specifics are reserved for the accompanying paper, with the general assumption that the app is successfully instrumented.
  3. Fuzzing Loop with Bug Oracles: With an initial intent specification and coverage feedback in place, MALintent enters its core fuzzing loop. It generates, mutates, and sends intents to the target app, continuously trying to invoke new behaviors and explore deeper code paths. Crucially, MALintent integrates several bug oracles to automatically detect different classes of vulnerabilities:
  • Crashes: These are detected when an application unexpectedly terminates. While often leading to denial-of-service, severe crashes can disrupt critical functions (e.g., preventing emergency calls in a dialer app).
  • Privacy Violations: This oracle identifies instances where sensitive user data (e.g., GPS location, camera feed, internal database information) is leaked or manipulated in an attacker-controlled manner, such as being written to an arbitrary file path or sent over the network to a malicious server.
  • Memory Safety Violations: Targeting vulnerabilities in native (C/C++) code, this oracle detects issues like buffer overflows that can lead to arbitrary code execution or data corruption.

For evaluation, MALintent was rigorously tested against a diverse set of 500 Android applications. This included applications from the F-Droid dataset (a repository of free and open-source Android apps) and a selection of the top 50 overall and top 50 productivity apps from the Google Play Store. Each application was subjected to a 16-hour fuzzing session. The results highlight the framework's effectiveness:

  • 9 Privacy Violations: Critically, these were found in highly mature and widely-used applications such as Chrome and WhatsApp, demonstrating that even well-vetted software can harbor these types of flaws.
  • 49 Crashes: A significant number of crashes were identified, predominantly Java-side null pointer exceptions and array index out-of-bounds errors. While most of these were classified as denial-of-service vulnerabilities, indicating poor error handling, they could still impact user experience and app reliability.
  • 1 Memory Safety Issue: A significant off-by-one error was discovered in an image processing library utilized by Facebook applications, including Instagram. This particular vulnerability, arising from incorrect rounding when resizing images, could lead to buffer overflows in native code, posing a more severe risk than simple Java crashes.

These findings underscore the pervasive nature of intent-related vulnerabilities and the efficacy of MALintent's coverage-guided, oracle-driven fuzzing approach in uncovering them across a broad spectrum of Android applications.

Technical Deep Dive

▶ Watch: MALintent's fuzzing loop and bug detection oracles (4:00)

MALintent's core innovation lies in its systematic approach to intent fuzzing, combining static and dynamic analysis with specialized techniques for different vulnerability classes.

Intent Specification Generation

The foundation of MALintent's fuzzing process is the intent specification. This specification acts as a structured blueprint defining the expected format and content of intents an application can receive. MALintent generates this specification by analyzing two primary sources:

  1. AndroidManifest.xml: This static manifest file declares an app's components (activities, services, broadcast receivers) and the intent filters they register. Intent filters explicitly state the actions, data schemes, and categories an app component is willing to handle. For example, a manifest might declare that an activity can handle android.intent.action.SEND for image/* MIME types. This provides a baseline understanding of the intents an app is designed to process.
  2. App Code Analysis: While the manifest provides a static declaration, the actual handling of intent extras and dynamic data flows occurs within the Java code. MALintent analyzes the app's compiled bytecode to identify how intent extras are read and used (e.g., intent.getStringExtra("path"), intent.getIntExtra("timeout", 0)). This dynamic analysis helps infer the expected data types and potential value ranges for specific keys within the intent's Bundle (extras).

By combining these two sources, MALintent constructs a JSON blob that precisely defines the intent structure, including required actions, categories, data URIs, and the names and types of expected extras. This detailed specification then guides the fuzzer in generating valid, yet potentially malicious, intent payloads.

Coverage Instrumentation

To achieve coverage-guided fuzzing, MALintent needs to monitor the execution paths within the target application. This feedback mechanism is crucial for intelligent mutation strategies, allowing the fuzzer to prioritize inputs that explore new code branches. The talk mentions a novel technique developed for Android coverage instrumentation, leveraging Java debugger APIs. While specifics are detailed in the paper, the high-level concept involves injecting hooks or utilizing debugging interfaces to track which basic blocks or methods are executed by the target app in response to a fuzzed intent. This coverage information is then fed back into the fuzzer to guide subsequent mutations, ensuring that the fuzzing process systematically explores the application's logic rather than randomly generating inputs.

The Fuzzing Loop and Specialized Bug Oracles

With the intent specification and coverage feedback, MALintent initiates its fuzzing loop. It generates initial intents based on the specification, sends them to the instrumented Android device, and then observes the application's behavior and collected coverage. Based on this feedback, it mutates subsequent intents (e.g., changing values in extras, altering data URIs, combining different actions) to explore new code paths and trigger latent vulnerabilities. The framework employs two particularly insightful specialized bug oracles:

Memory Safety Fuzzing for JNI

Many Android applications, especially those requiring high performance or leveraging existing libraries, incorporate native code written in C or C++. The bridge between Java code and native code is the Java Native Interface (JNI). JNI calls from Java methods invoke corresponding C/C++ functions. Traditional intent fuzzing can be inefficient for uncovering memory safety issues in native code because of the overhead: the intent must first traverse the Android IPC layer, be processed by the Java application logic, and only then might it reach a JNI call that triggers native code.

MALintent introduces a clever optimization for JNI fuzzing. The key insight is that JNI calls often exhibit complex data flow dependencies on the Java side. For example, a Java method might call native_open_file(path), which returns a native pointer, and this pointer is then passed to native_read_frame(pointer, buffer). Directly fuzzing native_read_frame in isolation is difficult without the correct pointer value.

MALintent addresses this by dynamically observing these data flow dependencies during initial fuzzing runs. When it detects a sequence of JNI calls where the output of one call serves as the input to another, it synthesizes a harness specifically for the native code. This harness directly calls the sequence of native functions, bypassing the Java-side overhead and the Android IPC layer. By generating inputs directly for this synthesized native harness, MALintent can fuzz the native library at a significantly faster rate, dramatically increasing the chances of finding memory safety bugs. This technique was instrumental in discovering the off-by-one error in the Instagram imaging library, where a buffer was allocated slightly too small due to incorrect rounding in native C/C++ code, leading to a potential buffer overflow.

Privacy Violation Detection via Dynamic Taint Analysis

Privacy violations are a critical concern in mobile security. These often arise when developers inadvertently expose sensitive data or functionality through intent handlers that were originally intended for internal use or assumed trusted input. An attacker, by crafting a malicious intent, can then exploit these handlers to gain unauthorized access to sensitive information or manipulate app behavior. Examples include:

  • A camera app that accepts a file path to store recorded video. An attacker could specify an arbitrary path, potentially outside the app's sandboxed storage, and retrieve the video without explicit camera permissions.
  • A camera app designed to take a picture after a timer, sending it back to the calling app. If this feature doesn't require user confirmation, an attacker could force the camera to take a picture and receive it, effectively escalating permissions.
  • A dialer app that can be pre-filled with a phone number. If it can be coerced into initiating a call without user consent, an attacker could call a controlled number and activate the user's microphone, turning it into a live bugging device.

MALintent tackles these by employing dynamic taint analysis. This technique tracks the flow of "tainted" (sensitive) data within the application.

  • Sensitive Data Sources: MALintent identifies and taints data originating from sensitive sources, such as GPS location, camera data, microphone input, and internal application databases.
  • Sensitive Sinks: It also defines "sinks" where sensitive data should not flow under attacker control. These include the file system (especially if the path can be controlled by an intent), the network (if the destination IP/port can be influenced), or even another intent (if it can be directed to an arbitrary malicious recipient).

During fuzzing, if MALintent observes a flow where tainted data from a sensitive source reaches a sensitive sink whose parameters are controlled by the fuzzed intent, it flags this as a privacy violation. This dynamic taint analysis provides a powerful and automated way to detect scenarios where attacker-controlled intent parameters can lead to the unauthorized leakage or manipulation of private user information.

Demo / Proof of Concept

▶ Watch: Example: Memory safety bug in Facebook's image library (6:00)

While the talk did not feature a live, interactive demonstration of the MALintent framework in action, the speaker effectively conveyed its capabilities and the severity of its findings through detailed descriptions of real-world vulnerabilities discovered. These examples serve as powerful proofs of concept for the framework's efficacy.

One prominent example was the Chrome vulnerability, where a malicious intent could lead to the leakage of cookies, browser state, and a visual dump onto the file system. This isn't just a theoretical flaw; it demonstrates a direct path to compromising user privacy and session integrity. The mechanism involved Chrome's IPC handling, where an attacker-controlled intent could manipulate internal state or direct output to an accessible location.

Another compelling proof of concept involved the permission escalation in camera applications. The scenario described an attacker using a timer-enabled intent to force a camera app to take a picture and return it, bypassing the usual user interaction required for capturing images. This effectively grants an attacker camera permissions without the user's explicit consent, showcasing a significant privacy breach. Similarly, the dialer app vulnerability, where an intent could initiate a call without user interaction, highlighted the potential for unauthorized microphone access, turning the user's phone into a listening device.

Finally, the memory safety issue in the Instagram imaging library provides a concrete example of a low-level vulnerability discovered by MALintent's specialized JNI fuzzing. An off-by-one error during image rounding caused a buffer to be allocated too small, leading to a potential buffer overflow. While not directly demonstrated, the identification of such a bug in a widely used native library underscores the framework's ability to delve into complex codebases and uncover critical vulnerabilities that traditional Java-only analysis might miss.

These examples, drawn from real applications like Chrome, WhatsApp, and Instagram, serve as compelling evidence of MALintent's ability to identify practical, high-impact security flaws, validating its design and implementation.

Defensive Implications

▶ Watch: Detecting and exploiting privacy violations with intents (6:30)

The findings from MALintent have profound implications for Android application developers, security auditors, and platform architects. They underscore that intent handling, often considered a benign mechanism for inter-app communication, is a critical attack surface requiring rigorous security scrutiny.

  1. Assume All Incoming Intents Are Malicious: The fundamental defensive posture for any Android application receiving intents should be one of zero trust. Developers must operate under the assumption that every incoming intent, regardless of its declared origin or perceived purpose, could be maliciously crafted. This applies equally to intents that are intended for "internal" communication within an app's own components, as these can often be invoked externally if not properly secured.
  1. Rigorous Input Validation: The most crucial defense against intent-based attacks is comprehensive input validation. Every piece of data extracted from an intent's extras, data URI, or action field must be thoroughly validated before use.
  • Path Validation: If an intent specifies a file path (e.g., for storing data, loading resources), ensure it's within the app's private, sandboxed directories or a designated safe location. Prevent path traversal vulnerabilities by sanitizing inputs to avoid ../ sequences.
  • Type and Range Checking: Validate numeric values (e.g., timeouts, image dimensions) to prevent integer overflows, underflows, or out-of-bounds access that could lead to crashes or memory safety issues.
  • URL/URI Scheme Validation: If an intent contains a URL, ensure its scheme and host are as expected, preventing redirection to malicious sites or unexpected resource loading.
  • MIME Type Verification: Always re-verify the MIME type of data received, even if specified in the intent, to prevent processing of unexpected or malicious file types.
  1. Explicit Permission Enforcement: Do not rely solely on intent filters or the Android manifest to enforce permissions. Before performing any sensitive operation (e.g., accessing the camera, microphone, GPS, internal databases, or network), explicitly check if the calling application (or the current application context) holds the necessary Android permissions using checkCallingOrSelfPermission(). This prevents permission escalation attacks where an attacker leverages an unprivileged app to trigger a privileged operation in a vulnerable target.
  1. Careful Handling of Sensitive Data Flows: Developers must be acutely aware of how sensitive data flows through their applications. Employing principles similar to MALintent's dynamic taint analysis, conduct manual or automated reviews to ensure that data originating from sensitive sources (camera, microphone, GPS, contacts, internal databases) cannot be directed to attacker-controlled sinks (arbitrary file paths, external network connections, or other intents that could be intercepted) based on fuzzed or malicious intent parameters.
  1. Secure JNI Implementations: For applications using native code via JNI, the security boundary between Java and C/C++ is critical. All data passed from Java to native methods must be validated on the Java side before the JNI call, and ideally, again within the native code. Memory management in native code (e.g., buffer allocations, pointer arithmetic) must be meticulously handled to prevent buffer overflows, use-after-free, and other memory safety vulnerabilities that could lead to remote code execution.
  1. Adopt Intent Fuzzing in Development Lifecycle: Incorporate intent fuzzing frameworks like MALintent into the continuous integration/continuous deployment (CI/CD) pipeline. Regular fuzzing can catch these vulnerabilities early in the development cycle, significantly reducing the cost and risk associated with patching post-release.
  1. Robust Error Handling: While Java-side crashes often result in denial-of-service, they indicate poor error handling. Implementing robust try-catch blocks and gracefully handling unexpected input can prevent app instability and improve user experience, even if it doesn't directly mitigate a privacy or memory safety issue.

By adopting these defensive strategies, developers can significantly harden their Android applications against a broad spectrum of intent-based attacks, enhancing overall platform security and user trust.

Key Takeaways

  • Android IPC (Intents) is a Critical Attack Surface: Despite Android's strong app isolation, Intents serve as the primary communication mechanism, making them a high-value target for attackers and a source of rising CVEs.
  • Coverage-Guided Fuzzing is Highly Effective: MALintent demonstrates that systematic, coverage-guided fuzzing, tailored for Android Intents, can efficiently uncover a wide range of vulnerabilities, including privacy violations, memory safety issues, and crashes, even in mature applications.
  • Novel JNI Fuzzing Accelerates Native Code Vulnerability Discovery: MALintent's innovative approach to synthesizing native code harnesses based on observed Java-side data flows significantly speeds up the identification of memory safety bugs in C/C++ libraries used via JNI.
  • Dynamic Taint Analysis is Key for Privacy Violations: The framework's use of dynamic taint analysis to track sensitive data flows to attacker-controlled sinks provides a powerful mechanism for automatically detecting privacy-related vulnerabilities and permission escalations.
  • Developers Must Validate All Intent Inputs: A fundamental defensive measure is to treat all incoming intents as potentially malicious and implement rigorous input validation for all intent parameters (paths, numerical values, URLs) to prevent exploitation.
  • Proactive Security for Intents is Essential: Integrating intent fuzzing into the development lifecycle and adopting a security-first mindset for intent handling are crucial steps for building more resilient Android applications.

About the Speaker(s)

Ammar Askar is a researcher who presented the MALintent framework at the NDSS Symposium. The transcript provides limited biographical information beyond his name, but his work on MALintent demonstrates expertise in Android security, inter-process communication, fuzzing techniques, and vulnerability research. His contributions highlight a deep understanding of Android's internal mechanisms and the practical implications of security flaws in widely used applications.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

Solid systems-security research with a novel contribution: coverage-guided intent fuzzing augmented by automated JNI harness synthesis and dynamic taint analysis for privacy oracles. Real CVE-grade findings in Chrome, WhatsApp, and Instagram validate the tooling. Not a 5 because the coverage instrumentation technique — the most technically interesting piece — is deferred to the paper rather than explained on stage.

Heather Calloway (CISO) — WEAK

Technically credible research that found real bugs in real apps — Chrome, WhatsApp, Instagram — using a novel coverage-guided intent fuzzing framework. But the talk is built for security researchers, not operators or decision-makers, and it never crosses the bridge into institutional relevance: no guidance on who owns this risk, no regulatory exposure analysis, no program-level action beyond generic developer hygiene.

→ Top-rated talks at Network and Distributed System Security (NDSS) Symposium 2025

All talks from Network and Distributed System Security (NDSS) Symposium 2025