When an MCP tool argument becomes an Android intent: mobile-mcp's injection sinks
CVE-2026-35394 lets a model-controlled URL fire arbitrary Android intents through mobile-mcp's mobile_open_url tool. Paired with a sibling path-traversal CVE, it shows a pattern: MCP tool arguments flowing unvalidated into platform sinks.
In brief
mobile-mcpis an MCP server for mobile development and automation. CVE-2026-35394, published in April 2026 (CWE-939, GitHub CNA vectorAV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H, High), lets a URL handed to themobile_open_urltool fire arbitrary Android intents —tel:,sms:, USSD codes,content:— because the tool never validates the URI scheme. It is fixed in 0.0.50. A sibling bug, CVE-2026-33989 (path traversal, fixed in 0.0.49), is the same class through a different sink. The lesson isn’t one package: it’s that MCP tool arguments are attacker-reachable, and any sink they reach must validate them.
What is this?
Mobile Next’s @mobilenext/mobile-mcp exposes a phone or emulator to an LLM agent as a set of MCP tools — tap, type, screenshot, open a URL. Per the GitHub Security Advisory GHSA-5qhv-x9j4-c3vm, versions prior to 0.0.50 pass the string given to the mobile_open_url tool straight to Android’s intent system with no scheme allowlist. Android resolves far more than http(s): tel: places a call, sms: opens a message, content: reaches a content provider, and dialer codes can trigger USSD actions. So a value the model was free to choose becomes a device action.
The same project shipped CVE-2026-33989 a few days earlier (NVD published 2026-03-27, fixed in 0.0.49): the saveTo and output parameters of the screenshot and screen-recording tools were written to disk without validation, allowing path traversal outside the workspace. Two CVEs, two tools, one root cause — unvalidated tool arguments reaching a powerful sink.
How it works
An MCP tool argument is not “trusted input.” It is whatever the model emitted, and the model’s context routinely contains untrusted text: a web page it browsed, an email it summarised, an issue it triaged. That is the indirect-prompt-injection surface — attacker text upstream, tool call downstream. When the tool forwards that argument into a sink without checking it, the injection lands as a real action.
For mobile_open_url, the dangerous step is the missing scheme check before dispatch:
// Vulnerable shape (< 0.0.50): scheme is never constrained
async function mobile_open_url(url) {
// url may be tel:, sms:, content:, or a dialer/USSD string —
// it is resolved by Android's intent system as-is.
await device.openUrl(url); // sink: arbitrary intent
}
// Fixed shape (0.0.50): allowlist the scheme first
function assertWebScheme(url) {
const ok = ["http:", "https:"];
if (!ok.includes(new URL(url).protocol)) throw new Error("scheme not allowed");
}
The CVSS vector (UI:R) reflects that a human still has to run the agent on the connected device, but no attacker privileges are required (PR:N) and the request is network-reachable (AV:N). The integrity and availability impact is High: the action executes on a real phone. We are not publishing a working chain; the point is the shape of the flaw, not a payload.
Why it matters
MCP’s value is that one agent can drive many tools. Its risk is that each tool independently decides whether to trust its arguments — there is no central mediator that says “this string came from model output, treat it as untrusted.” mobile-mcp happens to sit in front of an unusually powerful sink (a phone’s intent resolver), but the pattern is everywhere: a database MCP that interpolates an argument into SQL, a shell MCP that forwards one into a command, a filesystem MCP that joins one into a path. Each new tool is a fresh chance to reintroduce the class, which is exactly why this project produced two CVEs in two weeks.
The practical danger is a false boundary. Teams reason about “the agent” as the thing to secure and overlook that the MCP server is a confused deputy: it holds device or host privileges and will use them on instructions that ultimately trace back to untrusted content.
Defenses
- Upgrade.
mobile-mcp≥ 0.0.50 fixes the intent sink; ≥ 0.0.49 fixes the path-traversal sink. Pin the version and check withnpm list @mobilenext/mobile-mcp. - Allowlist at every sink, not just this one. Validate scheme for URL sinks (
http/httpsonly), canonicalise and confine paths for filesystem sinks, parameterise for query sinks. Treat each tool argument as untrusted model output. - Run MCP servers with least privilege. Drive a throwaway emulator rather than a personal device; deny telephony/SMS permissions the workflow doesn’t need; isolate filesystem and network so a bad argument can’t reach sensitive data.
- Audit your tool surface for the pattern. Grep your own and third-party MCP servers for arguments that flow into
openUrl,exec, file writes, or query builders without validation, and gate that check in CI so a future tool can’t reintroduce it. - Log and alert on out-of-band schemes. A
tel:,sms:,content:, or non-http(s)value reaching a URL tool — or a write outside the workspace — is a useful hunting signal that an argument was attacker-influenced.
Status
| Item | Reference | Date | Notes |
|---|---|---|---|
| CVE-2026-35394 | GHSA-5qhv-x9j4-c3vm | 2026-04 | mobile_open_url intent injection, CWE-939, vector C:L/I:H/A:H |
| Patched version | mobile-mcp 0.0.50 | — | Scheme validation added |
| CVE-2026-33989 | GHSA-3p2m-h2v6-g9mx | 2026-03-27 (NVD) | Path traversal in screenshot/recording tools, CWE-22/73 |
| Patched version | mobile-mcp 0.0.49 | — | Path validation added |
The right framing isn’t “patch mobile-mcp.” It’s that every MCP tool argument is reachable by whatever sits in the model’s context, and a tool that forwards one into a privileged sink without validation turns an upstream prompt injection into a downstream action — on a phone, a filesystem, or a database.
Sources
- → https://www.sentinelone.com/vulnerability-database/cve-2026-35394/
- → https://advisories.gitlab.com/pkg/npm/@mobilenext/mobile-mcp/CVE-2026-35394/
- → https://github.com/mobile-next/mobile-mcp/security/advisories/GHSA-5qhv-x9j4-c3vm
- → https://nvd.nist.gov/vuln/detail/CVE-2026-33989
- → https://github.com/mobile-next/mobile-mcp/security/advisories/GHSA-3p2m-h2v6-g9mx