Back to skill

Security audit

adb-phone-control

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly transparent about controlling an Android phone, but it includes broad automated app crawling and unsafe input/path handling that deserve review before use.

Install only if you understand that it can operate a real Android device, capture what is on screen, and leave those captures on disk. Avoid using the recursive explorer on personal, financial, messaging, or production apps, set ADB_OUTPUT_DIR to a private directory, and do not pass untrusted text or untrusted environment values to the helpers until the injection issues are fixed.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
adb-helpers.sh:317
Finding

Android Shell Command Injection Through Untrusted Text Input

Content
View full analysis
/dev/null; then # Use clipboard-based input for CJK adb shell "echo '$text' | am broadcast -a clipper.set" 2>/dev/null \ || adb shell input text "$escaped" echo "Typed (clipboard fallback): $text" else adb shell input text "$escaped" echo "Typed: $text" fi ``` ### Technical Analysis The `adb_input_text` function embeds the caller-controlled `text` value directly into a command string interpreted by the Android shell: ```bash adb shell "echo '$text' | am broadcast -a clipper.set" ``` The local double quotes only protect the argument from the local shell. Once transmitted through `adb shell`, the Android shell parses the embedded single quotes and metacharacters. A single quote in `text` can terminate the intended string, after which separators such as `;`, `&&`, pipes, or command substitutions can introduce additional commands. The vulnerable branch is selected for text detected as non-ASCII. An attacker can include a non-ASCII character alongside the shell payload to reach this branch. The fallback command also passes transformed, unvalidated text to `adb shell input text`; it should not be treated as a safe shell-escaping mechanism. ### Attack Path 1. The attacker controls or influences text supplied to `adb_input_text`. 2. The attacker includes at least one non-ASCII character so the clipboard fallback branch is selected. 3. The input contains a single quote that closes the `echo` argument, followed by Android shell syntax and an attacker-selected command. 4. The function constructs the complete string and sends it to `adb shell`. 5. The Android shell parses and executes ...[truncated 1087 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
adb-helpers.sh:119
Finding

Local Python Code Injection Through ADB_OUTPUT_DIR

Content
View full analysis
/dev/null 2>&1 python3 -c " import xml.etree.ElementTree as ET, sys def get_label(node): t = node.get('text', '') if t: return t d = node.get('content-desc', '') if d: return d.split(chr(10))[0] rid = node.get('resource-id', '') if rid: return rid.split('/')[-1] for child in node.iter(): if child is node: continue ct = child.get('text', '') if ct: return '>' + ct cd = child.get('content-desc', '') if cd: return '>' + cd.split(chr(10))[0] return '(unknown)' def parse_bounds(b): import re m = re.match(r'\[(\d+),(\d+)\]\[(\d+),(\d+)\]', b) if not m: return None x1,y1,x2,y2 = int(m[1]),int(m[2]),int(m[3]),int(m[4]) return (x1+x2)//2, (y1+y2)//2, b tree = ET.parse('$ADB_DUMP_FILE') idx = 0 for node in tree.iter('node'): if node.get('clickable') != 'true': continue label = get_label(node) bounds = node.get('bounds', '') result = parse_bounds(bounds) if not result: continue cx, cy, raw = result print(f'{idx:>2} {label:<40s} center=({cx},{cy}) bounds={raw}') idx += 1 " 2>/dev/null } ``` The same unsafe construction is present in `adb_clickable_json`: ```bash output=$(python3 -c " import xml.etree.ElementTree as ET, re, json ... tree = ET.parse('$ADB_DUMP_FILE') ... " 2>/dev/null) ``` ### Technical Analysis `ADB_OUTPUT_DIR` is an environment variable and is therefore potentially attacker-controlled. Its value is incorporated into `ADB_DUMP_FILE`, which is subse ...[truncated 2219 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill requires shell execution and produces files such as screenshots/UI dumps, but it does not declare an explicit tool scope or permissions boundary. That makes the operational capability broader and less auditable than the metadata suggests, increasing the risk of unintended command execution or data capture from a connected device.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 183)May include surrounding context.

md
- After page navigation: wait **2s**
- After typing: wait **0.5s**
- If UI hasn't changed after action: wait longer, up to **5s**, then re-check
- **Never blindly chain actions without verification**

### 4. Chinese / CJK Text Input

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helpers capture full UI hierarchies and screenshots from a connected Android device and persist them to local files in /tmp or another shared output directory without any consent prompt, warning, minimization, or cleanup. In this skill context, those artifacts can contain sensitive personal data, messages, authentication screens, and app state, so silent local persistence increases the risk of unintended disclosure to other local users, processes, or later tooling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The recursive exploration function delegates to an app exploration script that systematically clicks through an app and produces screenshots plus structured state output, but the wrapper provides no warning, consent gate, scope restriction, or safeguards against traversing sensitive screens. In an ADB phone-control skill, this is especially dangerous because it enables broad collection of device content at scale, potentially exposing private data across many app states rather than a single screen.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · app_explorer.py (reported line 80)May include surrounding context.

python
def adb(self, *args, timeout=15) -> str:
        try:
            result = subprocess.run(
                ["adb", "shell"] + list(args),
                capture_output=True, text=True, timeout=timeout
            )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · app_explorer.py (reported line 90)May include surrounding context.

python
def adb_host(self, *args, timeout=15) -> str:
        try:
            result = subprocess.run(
                ["adb"] + list(args),
                capture_output=True, text=True, timeout=timeout
            )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script automatically captures full-device screenshots and UI hierarchy dumps and saves them to disk, which can expose sensitive on-screen content such as messages, tokens, personal data, or app-specific secrets. In the context of a phone-control skill, this is more dangerous because the tool is designed to inspect arbitrary apps, including privacy-sensitive ones, without any consent gate, redaction, or data-minimization control.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The explorer blindly taps every clickable element, sends BACK events, and relaunches the app, which can trigger destructive or state-changing actions such as purchases, submissions, deletions, permission grants, or outbound navigation. In this skill context, that behavior is materially risky because live ADB control of a real device can affect actual user accounts and data, not just a sandboxed UI model.

Content

No source excerpt is available for this finding.