Module 14 — Android Components & IPC Security

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, and PendingIntent. 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

ComponentTypical risksTests (lab)Harden with
ActivityIntent spoofing, task hijacking, insecure deep linksam start -n, explicit/implicit intents, flagsandroid:exported="false", permission checks, safe intent filters, FLAG_SECURE, custom permissions
Service (started/bound)Unprotected operations, Binder misuseam startservice, am bind-service, AIDL call fuzzingSignature-level permissions, identity checks, input validation
BroadcastReceiverReceiver spoofing/eavesdropping, ordered broadcast abuseam broadcast --receiver-permission, sticky vs. non-stickyPrivate broadcasts, explicit receivers, permission-guarded actions
ContentProviderUnauthorized read/write, path traversal, SQL injection, insecure FileProvider grantscontent query, content insert, content call, file URI testsREAD/WRITE_* permissions, UriMatcher, projection whitelists, parameterized queries
PendingIntentMutable → intent replacement, hijackingCraft colliding intents from a lab appFLAG_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:

TypeNameExportedPermission requiredIntent actionsNotes

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 taskAffinity unless a real need exists.
  • Use FLAG_SECURE on sensitive UIs to prevent screenshots/overlay capture.
  • Validate Intent.getData() and getAction() robustly.

14.4.3 Deep links & App Links

  • Audit: <intent-filter> with VIEW actions, 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: .aidl files or onBind() 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 via PackageManager.
  • 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"> and intent-filter actions (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), and grantUriPermissions.

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 UriMatcher and 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 for root-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):

  1. Generate a content:// URI for a known file and attempt to open from a lab app with and without granted permissions.
  2. 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; avoid root-path unless 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 PendingIntent creation sites (static search for PendingIntent.get*).
  • Attempt to collide on the same requestCode/Intent and modify extras from a lab app.

Indicators of weakness:

  • PendingIntent created without FLAG_IMMUTABLE on API 23+.
  • Reuse of the same requestCode with FLAG_UPDATE_CURRENT.

Hardening:

  • Always set FLAG_IMMUTABLE unless 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 with PackageManager.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

  1. Unnecessary export
    • Fix: android:exported="false". Export only when required.
  2. Implicitly exported (pre-SDK 31) due to intent-filter
    • Fix: On SDK 31+, must set android:exported explicitly; for older targets, refactor to explicit components or add permission guards.
  3. No permission checks on bound service
    • Fix: Add android:permission on service + runtime caller verification.
  4. FileProvider with broad <paths>
    • Fix: Restrict <paths>; validate file names; apply minimal grantUriPermissions.
  5. Mutable PendingIntent
    • Fix: Add FLAG_IMMUTABLE; unique request codes; explicit component.
  6. SQL built via string concatenation
    • Fix: Use parameterized queries (? placeholders).
  7. 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.
  • FileProvider paths narrowed; grants are explicit and short-lived.
  • PendingIntent uses FLAG_IMMUTABLE and explicit component; unique request codes.
  • Deep links: App Links verified; parameters validated; step-up for sensitive flows.
  • Task/intent flags reviewed; no risky taskAffinity unless justified.
  • Unit/Instrumentation tests cover IPC permission boundaries.

14.13 Lab exercises (authorized, reproducible)

Lab 14-A — Intent spoofing triage

  • Use am start with 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 PendingIntent created by a demo app and change an extra.
  • Expected: With FLAG_IMMUTABLE the 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; verify grantUriPermissions scoping.
  • 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 start command, 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, mutable PendingIntent, 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>; avoid root-path.
  • Stale deep link assumptions → Users can receive links from anywhere; enforce auth/step-up server-side.
  • Ignoring PendingIntent flags → 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/content commands + logcat; hash artifacts.