Scope & ethics: This module is designed for authorized, lab-only testing and secure design review of Android applications—particularly high-risk apps such as banking. It covers how to systematically assess and harden Android components (Activities, Services, BroadcastReceivers, ContentProviders) and the IPC (Inter-Process Communication) surfaces they expose: Intents, Binder/AIDL, deep links,
FileProvider, andPendingIntent. We emphasize defensive patterns, repeatable lab procedures, and audit-grade evidence—not exploitation of production systems.
14.0 Learning objectives
After this module, you will be able to:
- Enumerate an app’s component attack surface and identify exported entry points.
- Test intent spoofing, insecure PendingIntent, task hijacking, insecure deep links, and ContentProvider issues (IDOR, path traversal, SQLi, lax URI permissions).
- Assess bound services and AIDL contracts (permission checks, parcel validation, binder identity).
- Use the Android shell (
pm,am,cmd,content) to interact with components in a lab, collect evidence, and build minimal PoC reproducers (lab apps). - Recommend concrete hardening:
android:exported, custom permission models,FLAG_IMMUTABLE,grantUriPermissions,UriMatcher, input validation, and secure deep-link intent filters. - Produce a component/IPC report with severity, impact, and developer-ready remediations.
14.1 Threat model for components & IPC
- External app adversary: Any app on the device may send Intents, bind to exported services, query content providers, or receive broadcasts unless protected.
- Confused deputy: Your app performs privileged action when triggered by an untrusted intent.
- IDOR via providers: Content exposed under
content://is readable/writable without permission or with mis-scoped permissions. - Task hijacking / overlay: Malicious app abuses task/intent flags or overlays to induce sensitive UI flows.
- PendingIntent confusion: Mutable
PendingIntents let other apps alter the final Intent used with your app’s privileges.
14.2 Component attack surface overview
| Component | Typical risks | Tests (lab) | Harden with |
|---|---|---|---|
| Activity | Intent spoofing, task hijacking, insecure deep links | am start -n, explicit/implicit intents, flags | android:exported="false", permission checks, safe intent filters, FLAG_SECURE, custom permissions |
| Service (started/bound) | Unprotected operations, Binder misuse | am startservice, am bind-service, AIDL call fuzzing | Signature-level permissions, identity checks, input validation |
| BroadcastReceiver | Receiver spoofing/eavesdropping, ordered broadcast abuse | am broadcast --receiver-permission, sticky vs. non-sticky | Private broadcasts, explicit receivers, permission-guarded actions |
| ContentProvider | Unauthorized read/write, path traversal, SQL injection, insecure FileProvider grants | content query, content insert, content call, file URI tests | READ/WRITE_* permissions, UriMatcher, projection whitelists, parameterized queries |
| PendingIntent | Mutable → intent replacement, hijacking | Craft colliding intents from a lab app | FLAG_IMMUTABLE, unique request codes, explicit Components |
14.3 Enumerating components (static & dynamic)
14.3.1 Static manifest analysis
Use output from Module 3 (apktool):
- Open
app_unpacked/AndroidManifest.xml. Collect all:<activity>,<service>,<receiver>,<provider>- Their
android:exported,permission,intent-filter,taskAffinity,allowTaskReparenting,launchMode.
- Note custom permissions (
<permission>,<uses-permission>), protection levels (normal,dangerous,signature,signatureOrSystem).
Create a table:
| Type | Name | Exported | Permission required | Intent actions | Notes |
|---|
14.3.2 Device-side enumeration (lab)
# list components known to the Package Manager
adb shell dumpsys package com.target.app | sed -n '/Activities:/,/Services:/p'
adb shell dumpsys package com.target.app | sed -n '/Services:/,/Receivers:/p'
adb shell dumpsys package com.target.app | sed -n '/Receivers:/,/Providers:/p'
adb shell dumpsys package com.target.app | sed -n '/Providers:/,$p'
# concise: query exported components
adb shell cmd package resolve-activity --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
adb shell pm dump com.target.app | grep -A2 -E "Activity|Receiver|Service|Provider" | grep exported
Record the package name, component class names, and whether a permission is required.
14.4 Activities: intent spoofing, task hijacking & deep links
14.4.1 Intent spoofing (lab)
Goal: Can an external app start a sensitive Activity with crafted extras?
# Try starting a target Activity explicitly (replace class)
adb shell am start -n com.target.app/.ui.TransferActivity \
--es account "12345" --es amount "1000.00" --ez confirm true
Evidence: Success/failure code, logcat (exceptions or toasts), screenshots.
Risk indicators: Action proceeds without caller identity or server confirmation; sensitive flow reachable without auth.
Hardening:
android:exported="false"for non-entry-point Activities.- If export is required (deep link), verify caller (e.g., signed origin via App Links) and validate extras.
- Use server-side confirmation for sensitive operations.
14.4.2 Task hijacking & unsafe flags
Watch for misuse of FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_SINGLE_TOP, taskAffinity, allowTaskReparenting.
- Test: Launch the Activity with unusual flags to see stack behavior:
adb shell am start -n com.target.app/.ui.LoginActivity \
-a android.intent.action.VIEW -d "bank://login" \
-f 0x10000000 # FLAG_ACTIVITY_NEW_TASK
Hardening:
- Keep default
taskAffinityunless a real need exists. - Use
FLAG_SECUREon sensitive UIs to prevent screenshots/overlay capture. - Validate
Intent.getData()andgetAction()robustly.
14.4.3 Deep links & App Links
- Audit:
<intent-filter>withVIEWactions, schemes/hosts in manifest. - Test: Trigger deep links:
adb shell am start -a android.intent.action.VIEW -d "bank://transfer?amount=10&to=abc"
adb shell am start -a android.intent.action.VIEW -d "https://bank.example.com/deeplink/transfer?amount=10"
Risks: Query params trusted without auth; open redirect; arbitrary URL loads in WebView.
Hardening:
- Use Android App Links (verified hosts).
- Treat deep links as navigation hints, not authorization; re-authenticate or step-up for sensitive actions.
- Strictly parse/whitelist parameters; ignore unknown.
14.5 Services: started vs. bound, Binder & AIDL
14.5.1 Started services
Test: Can a third-party app start privileged work?
adb shell am startservice -n com.target.app/.service.ExportService \
--es action "EXPORT_TRANSACTIONS" --ei count 100
Hardening:
- Add signature-level permission:
android:permission="com.target.app.permission.EXPORT". - In
onStartCommand, verify caller identity (Binder.getCallingUid()when applicable), and validate extras.
14.5.2 Bound services & AIDL
- Audit:
.aidlfiles oronBind()implementations. - Test: Attempt to bind without permission:
adb shell am bind-service -n com.target.app/.service.SecureBoundService
- If binding succeeds, attempt method calls from a lab client (simple Android test app) with crafted parcels.
Hardening:
- Require signature permissions for
bindService. - In service methods, check
getCallingUid()and map to package viaPackageManager. - Validate all Parcel inputs; treat
null/oversized values defensively. - Consider returning minimal data (principle of least privilege).
14.6 BroadcastReceivers: spoofing & leakage
14.6.1 Receiver spoofing
- Audit:
<receiver android:exported="true">andintent-filteractions (custom vs. public). - Test: Send crafted broadcast:
adb shell am broadcast -a com.target.app.ACTION_SYNC \
--es account "12345" --ez force true
Hardening:
- Prefer explicit broadcasts (component-name) for internal flows.
- Use permission-guarded broadcasts: sender or receiver permissions (
android:permission/android:exported="false"when possible). - Avoid sticky broadcasts for sensitive data.
14.6.2 Ordered broadcasts & priority abuse
If using ordered broadcasts, a malicious receiver with higher priority could consume/modify the result.
- Audit:
<intent-filter android:priority="…"> - Hardening: Keep default/low priorities; use explicit broadcasts for critical flows.
14.7 ContentProviders: IDOR, SQLi, and FileProvider
14.7.1 Enumerate providers & permissions
- From manifest and
dumpsys package, identify authority strings:content://com.target.app.provider/... - Note provider-level permissions (
readPermission,writePermission), andgrantUriPermissions.
14.7.2 Query & mutation tests (lab)
# list root paths
adb shell content query --uri content://com.target.app.provider/
# attempt read of sensitive table
adb shell content query --uri content://com.target.app.provider/accounts
# attempt filtered read (projection/selection)
adb shell content query --uri content://com.target.app.provider/tx \
--projection "id,amount,owner" --where "owner='test'"
# attempt insert/update/delete if exposed
adb shell content insert --uri content://com.target.app.provider/tx \
--bind amount:i:999 --bind owner:s:"attacker"
adb shell content delete --uri content://com.target.app.provider/tx/1
Evidence: Success codes, returned rows, exceptions.
Risks: Data readable without permission; write operations allowed; unparameterized queries → SQL injection; call() methods that bypass checks.
Hardening:
- Require explicit
READ_*/WRITE_*permissions (prefer signature level). - Implement a
UriMatcherand per-path permission checks. - Use parameterized queries and strict projection whitelists.
- Enforce row-level ownership on queries and mutations.
- Avoid
*projections; block arbitrary columns.
14.7.3 FileProvider pitfalls
- Audit:
<paths>XML forroot-path,files-path,cache-path, etc. - Risk: Over-broad paths allow unintended file sharing; improper URI grants lead to path traversal or leaked files.
Tests (lab):
- Generate a
content://URI for a known file and attempt to open from a lab app with and without granted permissions. - Check Intent extras that grant URI permissions (
FLAG_GRANT_READ_URI_PERMISSION/WRITE). Ensure they are only given to explicit recipients.
Hardening:
- Use the narrowest
<paths>possible; avoidroot-pathunless absolutely necessary. - Apply time-limited grants (
ClipData, flags) only to intended recipients; clear after use. - Validate requested filenames; prevent directory traversal (
../).
14.8 PendingIntent security
14.8.1 Risk model
A PendingIntent gives another app permission to execute an Intent using your app’s identity. If it’s mutable, attackers can replace Intent extras, actions, or even the component.
14.8.2 Tests (lab)
- Identify
PendingIntentcreation sites (static search forPendingIntent.get*). - Attempt to collide on the same requestCode/Intent and modify extras from a lab app.
Indicators of weakness:
PendingIntentcreated withoutFLAG_IMMUTABLEon API 23+.- Reuse of the same
requestCodewithFLAG_UPDATE_CURRENT.
Hardening:
- Always set
FLAG_IMMUTABLEunless mutation is strictly required; otherwise use tight explicit Intents and unique request codes. - Prefer explicit component and package in the underlying Intent.
- Avoid reusing
PendingIntents across different semantic operations.
14.9 Binder identity, permissions & caller verification
In bound service/AIDL methods, confirm the caller:
- Use
Binder.getCallingUid()and map to package withPackageManager.getPackagesForUid(). - Enforce signature-level permissions whenever two apps are expected to be from the same vendor.
- Defensive coding for Parcel inputs: null checks, length caps, type bounds.
Server-side linkage: never let client IPC directly authorize a sensitive operation; require server confirmation or session checks.
14.10 Common misconfigurations & how to fix them
- Unnecessary export
- Fix:
android:exported="false". Export only when required.
- Fix:
- Implicitly exported (pre-SDK 31) due to
intent-filter- Fix: On SDK 31+, must set
android:exportedexplicitly; for older targets, refactor to explicit components or add permission guards.
- Fix: On SDK 31+, must set
- No permission checks on bound service
- Fix: Add
android:permissionon service + runtime caller verification.
- Fix: Add
FileProviderwith broad<paths>- Fix: Restrict
<paths>; validate file names; apply minimalgrantUriPermissions.
- Fix: Restrict
- Mutable
PendingIntent- Fix: Add
FLAG_IMMUTABLE; unique request codes; explicit component.
- Fix: Add
- SQL built via string concatenation
- Fix: Use parameterized queries (
?placeholders).
- Fix: Use parameterized queries (
- Deep link trusts parameters
- Fix: Treat as navigation only; re-authenticate/step-up for sensitive actions.
14.11 Evidence collection & severity rubric
Collect: the exact am/content commands, logcat output (-v threadtime), screenshots, and if applicable, a tiny lab client APK used to trigger the issue. Hash artifacts.
Severity guide (mobile IPC):
- Critical: Unauthenticated mutation of sensitive provider data; any IPC path that executes privileged action leading to funds movement or PII exfiltration.
- High: Read of sensitive data from provider; bound service methods performing privileged actions without signature permission.
- Medium: Deep link enables sensitive navigation without step-up; PendingIntent mutable leading to behavior change.
- Low: Non-sensitive info leakage; defensive checks missing but no exploitable path demonstrated.
14.12 Developer hardening checklist (drop-in)
- Non-entry Activities
android:exported="false". - Exported components protected by signature or custom permissions where feasible.
- All Services verify caller UID/package in code.
- Broadcasts: internal → explicit; external → permission-guarded.
- ContentProvider: permission-gated,
UriMatcher, parameterized queries, projection allowlist, row-level checks. FileProviderpaths narrowed; grants are explicit and short-lived.- PendingIntent uses
FLAG_IMMUTABLEand explicit component; unique request codes. - Deep links: App Links verified; parameters validated; step-up for sensitive flows.
- Task/intent flags reviewed; no risky
taskAffinityunless justified. - Unit/Instrumentation tests cover IPC permission boundaries.
14.13 Lab exercises (authorized, reproducible)
Lab 14-A — Intent spoofing triage
- Use
am startwith crafted extras to trigger a sensitive Activity in a lab app. - Expected: Either blocked (good) or executed (finding). Capture logs + screenshots.
Lab 14-B — Provider read/write checks
- Enumerate provider URIs; attempt
content query/insert/delete. - Expected: Permission denial; if success with sensitive data → High/Critical finding.
Lab 14-C — PendingIntent mutation
- Build a tiny lab app to collide on a mutable
PendingIntentcreated by a demo app and change an extra. - Expected: With
FLAG_IMMUTABLEthe mutation fails; otherwise behavior changes (finding).
Lab 14-D — Bound service caller identity
- Attempt to bind/call AIDL methods from a lab app without declared permission.
- Expected: Binding fails or service rejects calls (verify in logs).
Lab 14-E — FileProvider scope
- Try to open unintended files via
content://paths; verifygrantUriPermissionsscoping. - Expected: Only intended files readable by recipients; no traversal.
14.14 Example commands (cheat-sheet)
# Start activity with extras
adb shell am start -n com.target.app/.ui.SettingsActivity --ez debug true
# Start a service with extras
adb shell am startservice -n com.target.app/.service.SyncService --es action "SYNC_NOW"
# Send broadcast
adb shell am broadcast -a com.target.app.ACTION_REFRESH --ez force true
# Bind service (probe)
adb shell am bind-service -n com.target.app/.service.SecureBoundService
# Query provider
adb shell content query --uri content://com.target.app.provider/accounts
# Insert/delete via provider
adb shell content insert --uri content://com.target.app.provider/notes --bind text:s:"hello"
adb shell content delete --uri content://com.target.app.provider/notes/1
# Logcat with timestamps
adb logcat -v threadtime | tee logs.txt
14.15 Reporting template (per finding)
- ID / Title: e.g., IPC-ACT-001 — Sensitive Activity reachable via spoofed Intent
- Component:
com.target.app/.ui.TransferActivity - Evidence:
am startcommand, logcat excerpt, screenshot - Impact: Unauthorized initiation of transfer flow; potential fraud
- Likelihood: Medium/High (any app can send Intent)
- Remediation: Set
android:exported="false"or require signature permission; validate extras; server-side confirmation - References: Manifest line numbers, code location, test replay steps
- Status: Open / Fixed (commit SHA), Retest date
14.16 Integration with CI & secure SDLC
- Automated lint rules: Flag missing
android:exported, mutablePendingIntent, providers without permissions, and string-built SQL. - Unit/instrumentation tests: Negative tests for binding without permission; deep link navigation tests; provider permission tests.
- Release gates: Block builds with exported components lacking permissions and mutable
PendingIntents. - Documentation: Maintain a Component Exposure Matrix per release (exported components, required permissions, rationale).
14.17 Common pitfalls & how to avoid them
- “It needs to be exported for feature X” → Export only the minimal component; wrap with signature permission; verify caller UID.
- Trusting extras → Treat all extras as untrusted input; re-fetch critical data server-side.
- Over-broad
FileProvider→ Narrow<paths>; avoidroot-path. - Stale deep link assumptions → Users can receive links from anywhere; enforce auth/step-up server-side.
- Ignoring
PendingIntentflags → Make immutable by default; be explicit and unique.
14.18 Deliverables from Module 14
- Component & IPC Surface Report (tables of components, exposure, permissions).
- PoC pack (lab-only): minimal lab client app/commands reproducing findings.
- Developer hardening checklist (above) integrated into PR templates.
- CI rules for exported components, providers, and PendingIntent flags.
- Retest plan aligned to remediation sprints.
14.19 “At a glance” cheat-sheet
- Export nothing by default.
- Guard exported components with signature/custom permissions + caller UID checks.
- Immutable PendingIntent with explicit component + unique request codes.
- Providers: permission-gated,
UriMatcher, parameterized queries, least-privilege projections. - Deep links: verified App Links; treat as navigation only; require auth/step-up.
- Collect evidence:
am/contentcommands + logcat; hash artifacts.
