Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

Phone Chrome CDP

v1.0.0

Control Android Chrome via ADB and raw WebSocket CDP. No Playwright needed for navigate, JS injection, cookies, DOM, scroll, click.

0· 73·0 current·0 all-time
by老实人@laolaoshiren

Install

OpenClaw Prompt Flow

Install with OpenClaw

Best for remote or guided setup. Copy the exact prompt, then paste it into OpenClaw for laolaoshiren/phone-chrome-cdp.

Previewing Install & Setup.
Prompt PreviewInstall & Setup
Install the skill "Phone Chrome CDP" (laolaoshiren/phone-chrome-cdp) from ClawHub.
Skill page: https://clawhub.ai/laolaoshiren/phone-chrome-cdp
Keep the work scoped to this skill only.
After install, inspect the skill metadata and help me finish setup.
Use only the metadata you can verify from ClawHub; do not invent missing requirements.
Ask before making any broader environment changes.

Command Line

CLI Commands

Use the direct CLI path if you want to install manually and keep every step visible.

OpenClaw CLI

Bare skill slug

openclaw skills install phone-chrome-cdp

ClawHub CLI

Package manager switcher

npx clawhub@latest install phone-chrome-cdp
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description (control Chrome on Android via ADB + CDP) match the SKILL.md: it shows adb port forwarding, listing tabs via /json, and a Python CDP client to send CDP commands. There are no unrelated environment variables, binaries, or installs requested.
Instruction Scope
The instructions stay on-topic (start Chrome via ADB, forward devtools socket, manually implement WebSocket frames, call CDP methods, use adb screencap). However the doc explicitly (1) instructs bypassing browser protections by omitting Origin headers, (2) shows how to read httpOnly cookies and execute arbitrary JS in pages, and (3) encourages exposing localhost:9222 to the LAN via port-forwarding — all of which are legitimate for a CDP tool but are powerful and sensitive operations. The instructions do not include explicit steps to exfiltrate data, but the provided code and commands give full ability to read cookies, DOM, and perform actions, so operator caution is needed.
Install Mechanism
There is no install spec and no code files beyond SKILL.md; the skill is instruction-only. That minimizes filesystem/installation risk because nothing will be written/installed by a package step in the skill bundle itself.
Credentials
The skill does not request environment variables, credentials, or config paths. The operations it performs (adb, local HTTP/WebSocket to Chrome DevTools) do not require additional external credentials declared by the skill, so the lack of requested secrets is proportionate.
Persistence & Privilege
The skill is not always-enabled, does not request persistent presence, and contains no instructions to modify other skills or global agent config. Autonomous invocation is allowed (platform default) but not combined with other privilege escalation requests.
Assessment
This skill appears to do exactly what it claims, but it grants strong access to the phone's browser: it shows how to run JS in pages and read httpOnly cookies, and it suggests exposing the DevTools port to the LAN. Before using it, consider: - Only run these instructions on devices and networks you trust. Exposing Chrome DevTools (localhost:9222) to other hosts lets anyone on that network fully control the browser and read sensitive data. - Prefer keeping the DevTools endpoint bound to localhost and use an authenticated tunnel (SSH/VPN) if remote access is required, instead of opening it directly to the LAN. - The SKILL.md recommends omitting the Origin header to bypass browser rejection — this is deliberate to connect over ADB but removes a browser protection; be careful when reusing code or adapting it for other environments. - The steps let you read cookies (including httpOnly) and DOM contents and perform clicks/navigation — treat outputs as sensitive and avoid sending them to untrusted endpoints. - Because this is instruction-only, the skill itself doesn't install code, but it runs shell commands (adb, curl) and provides Python code you or an agent would execute. Only run the provided code after reviewing and, if possible, running in an isolated environment. If you want to proceed safely: restrict port forwarding to localhost, avoid direct LAN exposure, require explicit confirmation before any action that forwards ports or reads cookies, and audit any network forwarding tools used for sharing.

Like a lobster shell, security has layers — review code before you run it.

adbvk97cghnb5qpr60nxpzr03rhc8584z4yfandroidvk97cghnb5qpr60nxpzr03rhc8584z4yfcdpvk97cghnb5qpr60nxpzr03rhc8584z4yfchromevk97cghnb5qpr60nxpzr03rhc8584z4yflatestvk97cghnb5qpr60nxpzr03rhc8584z4yfplaywright-alternativevk97cghnb5qpr60nxpzr03rhc8584z4yfzero-dependencyvk97cghnb5qpr60nxpzr03rhc8584z4yf
73downloads
0stars
1versions
Updated 1w ago
v1.0.0
MIT-0

Phone Chrome CDP

通过 ADB 连接手机 Chrome DevTools Protocol,用原始 WebSocket 控制浏览器。

Step 1: Setup

启动 Chrome 并转发端口:

adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main
sleep 3
adb forward --remove tcp:9222 2>/dev/null
adb forward tcp:9222 localabstract:chrome_devtools_remote

验证:curl -s http://localhost:9222/json/version

获取 tab 列表:curl -s http://localhost:9222/json/list

Step 2: CDPClient Class

关键点:手动构造 WebSocket 帧,不加 Origin 头(Chrome Android 会拒绝带 Origin 的连接)。

import socket, base64, os, struct, json, time

class CDPClient:
    def __init__(self, host, port, tab_id):
        self.sock = socket.create_connection((host, port), timeout=10)
        key = base64.b64encode(os.urandom(16)).decode()
        path = "/devtools/page/" + str(tab_id)
        req = "GET " + path + " HTTP/1.1\r\nHost: " + host + ":" + str(port) + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: " + key + "\r\nSec-WebSocket-Version: 13\r\n\r\n"
        self.sock.sendall(req.encode())
        resp = b""
        while b"\r\n\r\n" not in resp:
            resp += self.sock.recv(4096)
        self._msg_id = 0

    def send(self, method, params=None):
        self._msg_id += 1
        cmd = {"id": self._msg_id, "method": method}
        if params:
            cmd["params"] = params
        data = json.dumps(cmd).encode()
        mask = os.urandom(4)
        frame = bytearray([0x81])
        length = len(data)
        if length < 126:
            frame.append(0x80 | length)
        elif length < 65536:
            frame.append(0x80 | 126)
            frame.extend(struct.pack(">H", length))
        frame.extend(mask)
        frame.extend(b ^ mask[i % 4] for i, b in enumerate(data))
        self.sock.sendall(bytes(frame))
        return self._msg_id

    def recv_until(self, target_id, timeout=10):
        deadline = time.time() + timeout
        while time.time() < deadline:
            self.sock.settimeout(max(0.1, deadline - time.time()))
            try:
                header = self.sock.recv(2)
                if len(header) < 2:
                    continue
                length = header[1] & 0x7f
                if length == 126:
                    length = struct.unpack(">H", self.sock.recv(2))[0]
                if header[1] & 0x80:
                    self.sock.recv(4)
                data = bytearray()
                while len(data) < length:
                    chunk = self.sock.recv(length - len(data))
                    if not chunk:
                        break
                    data.extend(chunk)
                msg = json.loads(data.decode())
                if msg.get("id") == target_id:
                    return msg
            except socket.timeout:
                continue
        return None

    def drain(self, timeout=1):
        deadline = time.time() + timeout
        while time.time() < deadline:
            self.sock.settimeout(0.1)
            try:
                self.sock.recv(4096)
            except:
                pass

    def eval_js(self, expression):
        msg_id = self.send("Runtime.evaluate", {"expression": expression, "returnByValue": True})
        resp = self.recv_until(msg_id)
        if resp and "result" in resp:
            return resp["result"].get("result", {}).get("value")
        return None

    def navigate(self, url):
        self.send("Page.navigate", {"url": url})
        time.sleep(3)

    def close(self):
        self.sock.close()

Step 3: Usage Examples

cdp = CDPClient("localhost", 9222, tab_id=110)

# 读页面信息
title = cdp.eval_js("document.title")
url = cdp.eval_js("window.location.href")

# 导航
cdp.navigate("https://www.baidu.com")

# 注入 JS 搜索
cdp.eval_js("document.querySelector('#kw').value = '美食'")
cdp.eval_js("document.querySelector('#su').click()")
time.sleep(4)

# 读搜索结果
results_json = cdp.eval_js("JSON.stringify(Array.from(document.querySelectorAll('h3 a')).slice(0,5).map(a=>({title:a.textContent,href:a.href})))")

# 读 Cookie(含 httpOnly)
cdp.send("Network.enable")
cdp.drain(0.5)
msg_id = cdp.send("Network.getAllCookies")
all_cookies = cdp.recv_until(msg_id)
cookie_count = len(all_cookies["result"]["cookies"])

# 写 Cookie
cdp.eval_js("document.cookie = 'test=hello; path=/'")

# 滚动
cdp.eval_js("window.scrollBy(0, 500)")

# 读页面文本
text = cdp.eval_js("document.body.innerText.substring(0, 2000)")

cdp.close()

截图(非 CDP)

用 adb screencap:

adb shell input keyevent KEYCODE_WAKEUP
adb shell screencap -p /sdcard/screen.png
adb pull /sdcard/screen.png ./screen.png

LAN 共享

当前机器当跳板,用端口转发工具把 localhost:9222 暴露给局域网。其他机器连接 your_ip:转发端口。

已验证

  • 导航 / 读标题URL / 注入JS / 读写Cookie / 点击 / 滚动 / 读DOM
  • 截图通过 screencap(非 CDP 原生)

  1. websocket-client 库连不上(403):因为自动加 Origin 头。用 CDPClient 手动构造帧
  2. /json/list 超时:重启 Chrome
  3. screencap 黑屏:先唤醒屏幕
  4. Chrome 重启后 tab ID 变:重新查 tab 列表

Comments

Loading comments...