Security Implications of ADB Debugging for scrcpy: A Complete Technical Analysis

Enabling USB debugging for scrcpy grants the host computer full ADB privileges, creating a trust boundary where a compromised host can execute arbitrary code, capture the screen, or inject input on the connected Android device.

scrcpy is a lightweight screen mirroring tool developed by Genymobile that relies entirely on the Android Debug Bridge (ADB) to communicate with Android devices. Because scrcpy does not implement additional sandboxing beyond what ADB provides, understanding the security implications of ADB debugging is essential for safe deployment. This analysis examines the specific attack vectors present in the scrcpy source code and provides actionable mitigation strategies.

How scrcpy Leverages ADB Privileges

scrcpy operates as a thin client that mirrors an Android device on a computer, with all communication traversing the ADB daemon. According to the Genymobile/scrcpy source code, the tool functions as an ADB client that pushes a Java server to the device (/data/local/tmp/scrcpy-server.jar), establishes socket connections via port forwarding, and issues shell commands to control the device.

The main client logic resides in app/src/server.c, where the push_server() function (lines 58-68) pushes the server JAR to the device using sc_adb_push. Because ADB operates with elevated privileges on devices with Developer options → USB debugging enabled, scrcpy inherits these capabilities automatically. The server JAR executes with the same privileges as the ADB shell, granting the host computer substantial control over the target device.

Critical Attack Vectors in scrcpy's ADB Integration

Server Push and Arbitrary Code Execution

In app/src/server.c#L58-L68, the push_server() function transfers the scrcpy server to /data/local/tmp/ using sc_adb_push. The device trusts any file received via adb push, meaning a malicious host that replaces the legitimate JAR with a modified version can execute arbitrary code on the device. This represents a supply chain attack vector where the host's file system integrity becomes critical to device security.

Command Injection Risks

scrcpy uses sc_adb_execute() (defined in app/src/adb/adb.c#L228-229) to run shell commands on the device, including operations for TCP/IP toggling and device configuration (referenced at server.c#L456). To mitigate shell injection, the codebase implements validate_string() in server.c#L89-100, which sanitizes command-line parameters before execution. However, any vulnerability in this validation logic could allow an attacker to run arbitrary shell commands on the device.

Port Forwarding Exposure

scrcpy creates local UNIX sockets on the host and forwards them to the device using sc_adb_forward (app/src/adb/adb.c#L249-251) and reverse tunnels via sc_adb_reverse (app/src/adb/adb_tunnel.c#L22-23). These forwarded ports expose the device’s internal services—including the video stream socket—to the host’s network stack. If the host machine is compromised, an attacker can capture the video stream or inject control messages by connecting to these local ports.

TCP/IP Mode Network Exposure

When using the --tcpip flag, scrcpy automatically enables adb over network on the device, documented in doc/connection.md (lines 70-78). This operation internally executes adb tcpip 5555, opening the ADB daemon on port 5555 to the local network. An attacker on the same LAN can then connect to the device without physical access, bypassing the USB cable requirement and expanding the attack surface from local to network-based threats.

Device Authentication and Trust Boundaries

Device Selection via ANDROID_SERIAL

scrcpy reads the ANDROID_SERIAL environment variable or executes adb devices to select a target device, as documented in doc/connection.md (lines 5-33). An attacker who controls the host environment can manipulate this variable to force scrcpy to connect to an arbitrary device visible via ADB, potentially intercepting screenshots or redirecting input to a malicious target.

Input Injection and Media Projection Permissions

While the scrcpy server JAR runs as a normal app without root access, it requests media projection and input injection capabilities that require one-time user approval. Once authorized, any process capable of communicating with the scrcpy server—such as other local programs on the host—can capture the screen or inject input events. This occurs because the server trusts the local socket forwarded by ADB, creating a privilege escalation path from host user to device control.

Cleanup and Persistent Exposure

scrcpy attempts to clean up resources by calling sc_adb_kill_server() on exit (app/src/server.c#L936), which removes forwarded sockets. However, if scrcpy crashes or is terminated abruptly (SIGKILL), these forwarded ports may remain open indefinitely, leaving the device exposed until the user manually restarts ADB or reboots the device.

Practical Security Hardening for scrcpy

Use these code examples to minimize your attack surface when operating scrcpy.

Basic USB-only connection (least risky):


# Connect device via USB only, no network exposure

scrcpy

Explicitly disable TCP/IP mode before connecting:


# Force ADB back to USB mode to prevent accidental network exposure

adb usb
scrcpy

Manual TCP/IP with controlled network access:


# Only enable if your network is trusted and secured

adb tcpip 5555
adb connect 192.168.1.42:5555
scrcpy

Verify and restrict port forwarding:


# Check existing forwards that might expose the device

adb forward --list

# Remove all forwards when done

adb forward --remove-all

Summary

  • ADB is the trust anchor: scrcpy does not add extra sandboxing; it fully trusts the ADB connection, inheriting all associated privileges and risks.
  • Server push vulnerability: The push_server() mechanism in server.c allows arbitrary code execution if the host serves a malicious JAR.
  • Network exposure: Enabling ADB over Wi-Fi via --tcpip opens port 5555, allowing any device on the same LAN to attempt ADB connections.
  • Port forwarding risks: Local sockets forwarded via sc_adb_forward and sc_adb_reverse expose video and control channels to the host, enabling eavesdropping if the host is compromised.
  • Cleanup failures: Abrupt termination may leave forwarded ports open, requiring manual intervention to secure the device.

Frequently Asked Questions

Does scrcpy require root access on the Android device?

No, scrcpy does not require root access. The server runs as a regular application using ADB shell permissions, but it can request media projection and input injection capabilities once authorized by the user. These permissions grant significant control without requiring root, as implemented in the server logic at app/src/server.c.

Can someone hack my phone through scrcpy if they are on the same Wi-Fi network?

Yes, if you enable ADB over TCP/IP using scrcpy --tcpip or adb tcpip 5555, the ADB daemon listens on port 5555. Anyone on the same network can attempt to connect using adb connect <your-ip>:5555. While ADB requires RSA key authentication for initial pairing, a persistent attacker could potentially exploit this exposure, as documented in the connection flow at doc/connection.md.

How does scrcpy prevent command injection when executing ADB shell commands?

scrcpy mitigates shell injection through the validate_string() function located at server.c#L89-100, which sanitizes parameters passed to sc_adb_execute() (adb.c#L228-229). However, this validation is the primary defense line; any bug in this sanitization logic could expose the device to arbitrary command execution from a malicious host.

What happens to port forwards if scrcpy crashes unexpectedly?

If scrcpy terminates abnormally without executing the cleanup routine sc_adb_kill_server() at server.c#L936, the forwarded ports created by sc_adb_forward and sc_adb_reverse may remain active. This leaves the device's scrcpy socket exposed on the host until you manually run adb forward --remove-all or restart the ADB daemon.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →