YinkoShield

Knowledge Center / Mobile runtime attacks / mobile runtime attacks · 2026·01

Screen-capture attacks — MediaProjection abuse

Android's MediaProjection API lets a foreground app capture the device's screen with the user's consent. The consent is per-session, not per-frame: once the user accepts, the calling app holds a token that lets it keep capturing — across foreground transitions, across other apps' sensitive content — until the calling app explicitly stops the session. The abuse pattern is a session that does not stop when the user thinks it has.

[ MediaProjection — screen-capture lifecycle ] 1 · intent createScreen CaptureIntent() 2 · user consent platform shows "start recording?" user taps Start 3 · token getMediaProjection() → session active 4 · capture VirtualDisplay frames flow ⇢ 5 · persists until stop() // the abuse pattern user accepts once → session token persists across the app lifecycle VirtualDisplay can keep capturing across multiple foreground apps until the host calls stop() substrate signal: runtime.environment { mediaprojection.active : true · started_at : ts }
A MediaProjection session takes user consent once. Once the token is acquired, the host app can keep capturing across foreground transitions until it explicitly calls stop().

1. Mechanism

The MediaProjection lifecycle [1] is short:

  1. The app calls MediaProjectionManager.createScreenCaptureIntent() to construct a system intent that prompts the user.
  2. The platform displays the consent dialog (“Start recording or casting with [App name]?”). The user taps Start or Cancel.
  3. If accepted, getMediaProjection() returns a token. From Android 14 (API 34), a foreground service of type FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION must already be running when this call is made, and the consent token is single-use — re-creating a VirtualDisplay after stop() requires re-prompting the user. From this point, the app can construct a VirtualDisplay bound to the token and consume the frames as a Surface.
  4. The session continues until the app calls MediaProjection.stop() or the platform terminates the host process. On Android 14+, the user can also dismiss the persistent cast notification or revoke consent via Settings, either of which terminates the session.

The abuse pattern (largely pre-Android-14): once the user accepts, the app — through a foreground-service binding — keeps the session alive. The user backgrounds the host app, opens a banking app, types credentials. The host app’s VirtualDisplay is still bound to the device’s screen surface. Every frame, including the banking app’s, is captured.

Android 14 (API 34) tightened the model [2]: foreground-service type FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION declared, FGS started before getMediaProjection(), single-use consent token, and a per-app cast notification. Android 14 QPR1 / Android 15 added a single-app capture mode in which the user can choose to share only one app’s surface rather than the full screen; sensitive apps not selected for capture are excluded at the compositor level. The classic full-screen-capture-after-consent pattern is more constrained on modern Android; the residual risk is on pre-A14 builds and on flows where the user grants single-app capture for the banking app itself.

2. Where in the runtime it operates

The relevant components:

  • MediaProjectionManager — the platform service the app binds to.
  • The session token — held in the host app’s process memory.
  • VirtualDisplay — composited by SurfaceFlinger, receiving frames from the device’s display.

FLAG_SECURE on a window blocks MediaProjection capture: while a FLAG_SECURE window is on top, the entire captured virtual display is rendered black for the duration the secure window is foregrounded [4] — the protection applies to the whole projected frame, not just the secure window’s region. A banking activity that sets FLAG_SECURE on its sensitive screens denies frames to a third-party MediaProjection session for the time those screens are visible. This is a real, effective mitigation; the gap is the apps that forget to set the flag.

3. Which checkpoints it bypasses

  • Play Integrity / App Attest. Pass cleanly. The MediaProjection call is a legitimate platform API.
  • FIDO2. The capture observes the credential prompt the user dismissed; the assertion itself is unrelated.
  • EMV / 3DS. Same — these checkpoints don’t observe the screen.

4. Which signals make it observable

runtime.environment. The Trusted Runtime Primitive observes active MediaProjection sessions on the device, the host package that holds the session token, the time the session was started, and whether the session is currently capturing. When a sensitive event fires while a third-party MediaProjection session is active, the substrate emits the signal.

5. Evidence Token shape when observed

The following example is illustrative; field names, type values, and schema are defined in YEI-001 §4 (available through the spec-access process).

{
  "ev": [{
    "ts":   "2026-06-15T10:23:14Z",
    "class": "runtime.environment",
    "type":  "mediaprojection.active",
    "data": {
      "host_package":      "com.example.cast",
      "host_signed_by":    "F1:23:…:AB",
      "session_started":   "2026-06-15T10:18:02Z",
      "during":            "credential_entry",
      "host_flag_secure":  true
    }
  }]
}

The host_flag_secure is whether the app receiving the credential set its window flag. When it is true, the MediaProjection session captures black frames while the secure window is foregrounded; the operator may still want to know that a session was active. Execution Evidence Infrastructure (EEI) — the device-identity infrastructure layer for banking and payments — signs the session-active fact and the host’s FLAG_SECURE posture together so the operator’s verifier reads both.

6. Cross-references

7. External references

[1] Android Developers. MediaProjection. developer.android.com/reference/android/media/projection/MediaProjection. Cited 2026-01-21.

[2] Android Developers. Android 14 — MediaProjection foreground service requirements. developer.android.com/about/versions/14/changes/fgs-types-required. Cited 2026-01-21.

[3] OWASP MASTG. Testing Data Storage and Privacy. mas.owasp.org/MASTG/Android/0x05d-Testing-Data-Storage/. Cited 2026-01-21.

[4] Android Developers. WindowManager.LayoutParams.FLAG_SECURE. developer.android.com/reference/android/view/WindowManager.LayoutParams#FLAG_SECURE. Cited 2026-01-21.