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.
stop().
1. Mechanism
The MediaProjection lifecycle [1] is short:
- The app calls
MediaProjectionManager.createScreenCaptureIntent()to construct a system intent that prompts the user. - The platform displays the consent dialog (“Start recording or casting with [App name]?”). The user taps Start or Cancel.
- If accepted,
getMediaProjection()returns a token. From Android 14 (API 34), a foreground service of typeFOREGROUND_SERVICE_TYPE_MEDIA_PROJECTIONmust already be running when this call is made, and the consent token is single-use — re-creating aVirtualDisplayafterstop()requires re-prompting the user. From this point, the app can construct aVirtualDisplaybound to the token and consume the frames as aSurface. - 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 bySurfaceFlinger, 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
- Sibling articles:
snapshot-timing-exploits,overlay-injection - Architecture:
/architecture/runtime-coherence - Glossary:
/glossary— runtime.environment
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.