Back to skill

Security audit

AI Browser

Security checks for vulnerabilities and agentic risk

Overview

This browser-control skill mostly does what it says, but it exposes powerful browser access with weak boundaries and insufficient warnings.

Only install this for a trusted, isolated local environment. Do not use it with sensitive accounts, private intranet sites, passwords, tokens, or confidential forms unless the WebSocket and debugging ports are restricted, authentication is added, snapshots are redacted, evaluate is removed or tightly gated, and Chromium is run with stronger sandboxing.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.js:93
Finding
Unauthenticated WebSocket Endpoint Exposes Full Browser Control<![CDATA[ ## Vulnerability Details **File Location**: `server.js:93-98` **Vulnerability Type**: Missing authentication and network access controls **Risk Level**: Critical ### Vulnerable Code ```js // 启动 WebSocket 服务器 const wss = new WebSocket.Server({ port: PORT }); console.log(`🦞 AI Browser Server 启动在 ws://localhost:${PORT}`); wss.on('connection', (ws) => { console.log('🔌 新的客户端连接'); ``` ### Technical Analysis The WebSocket server is created with only a port number. It does not explicitly bind to `127.0.0.1`, so it may listen on all available network interfaces. The console message and documentation describe the service as running on localhost, but the implementation does not enforce that restriction. The connection handler performs no authentication, authorization, token validation, client-origin validation, or connection-level permission checks. Once connected, a client can invoke every supported browser action. The browser and active page are also stored in global variables, meaning all clients operate on the same browser session. An unauthorized client can therefore interact with pages opened by a legitimate user, including pages containing authenticated sessions. ### Attack Path 1. An attacker identifies a host exposing TCP port `18790`. 2. The attacker establishes a WebSocket connection without supplying credentials. 3. The attacker sends `status`, `snapshot`, or `screenshot` requests to inspect the active browser. 4. The attacker uses `navigate`, `click`, `type`, or `evaluate` to manipulate the shared browser session. 5. If the browser contains an authenticated session, the attacker performs actions with the victim's web application privileges. ### Impact Assessment A network-reachable attacker can obtain complete control over the shared browser session. This may permit: - Reading data displayed in authenticated web applications. - Extracting form values and page contents. - Capturing screenshots. - Performing transactions or changing a ...[truncated 263 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Explicitly bind the server to loopback unless remote operation is strictly required: ```js const wss = new WebSocket.Server({ host: '127.0.0.1', port: Number(PORT) }); ``` 2. Require a high-entropy authentication token during the WebSocket handshake. 3. Reject connections with missing or invalid credentials before registering message handlers. 4. Validate the WebSocket `Origin` header against an explicit allowlist. 5. Use TLS when any remote access is permitted. 6. Create a separate incognito browser context and page for each authenticated client. 7. Apply authorization checks per action rather than treating authentication as permission to invoke every capability. 8. Add connection limits, message-size limits, rate limiting, and security audit logging. 9. Apply host firewall rules so port `18790` is not reachable from untrusted networks. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.js:77
Finding
Arbitrary JavaScript Execution in the Active Browser Page<![CDATA[ ## Vulnerability Details **File Location**: `server.js:77-80` **Vulnerability Type**: Unrestricted page-context code execution **Risk Level**: Critical ### Vulnerable Code ```js case 'evaluate': if (!wsPage) throw new Error('没有活动的页面'); const result = await wsPage.evaluate(params.script); return { result }; ``` ### Technical Analysis The `evaluate` action passes attacker-controlled `params.script` directly to Puppeteer's `page.evaluate()` without validation or an operation allowlist. The code runs in the JavaScript context of the active web page. Although this is not directly equivalent to Node.js code execution, it provides the same capabilities as script running within the page origin. It can read DOM content, inspect non-HttpOnly application data, invoke application APIs available to the page, alter forms, and initiate authenticated user actions. Because the WebSocket endpoint has no authentication and all connections share the global browser page, this capability is exposed to any client able to reach the service. ### Attack Path 1. An attacker connects to the unauthenticated WebSocket service. 2. The attacker navigates the shared page to a target application or waits for a legitimate user to open an authenticated page. 3. The attacker submits an `evaluate` request containing arbitrary JavaScript. 4. The script reads sensitive page data or invokes application behavior in the victim's authenticated context. 5. The evaluated result is serialized and returned to the attacker over WebSocket. For example, an attacker could submit a script that returns `document.documentElement.innerText`, enumerates local storage, or programmatically submits a sensitive form. ### Impact Assessment The attacker gains script-level control over the active page and can operate with the privileges of the page's authenticated web session. Potential consequences include: - Disclosure of private page content and DOM-accessible tokens. - Theft of data stor ...[truncated 397 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the general-purpose `evaluate` action. 2. Replace it with narrowly scoped, predefined browser operations. 3. Validate every action using a strict schema and reject unknown properties. 4. If evaluation is unavoidable, expose only reviewed script identifiers rather than accepting script source text. 5. Run each client in a fresh, isolated browser context without inherited cookies or credentials. 6. Require authentication and per-action authorization. 7. Restrict permitted destination origins and prevent evaluation on sensitive or internal applications. 8. Apply execution timeouts and result-size limits to reduce denial-of-service risk. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.js:45
Finding
Unrestricted Navigation Enables Access to Internal Network Resources<![CDATA[ ## Vulnerability Details **File Location**: `server.js:45-48` **Vulnerability Type**: Browser-mediated server-side request forgery **Risk Level**: High ### Vulnerable Code ```js case 'navigate': if (!wsPage) throw new Error('没有活动的页面'); await wsPage.goto(params.url, { waitUntil: 'networkidle2' }); return { success: true, url: wsPage.url(), title: await wsPage.title() }; ``` ### Technical Analysis The server accepts a caller-controlled URL and directs Chromium to navigate to it without validating the protocol, hostname, resolved IP address, port, or redirect destination. The request originates from the machine running Chromium rather than from the WebSocket client. Consequently, the browser may be able to reach loopback services, private network systems, link-local endpoints, or cloud metadata services that are inaccessible to an external attacker. The response can then be inspected through the service's `snapshot`, `screenshot`, and `evaluate` capabilities. This creates a complete browser-mediated SSRF path rather than a blind request primitive. ### Attack Path 1. An attacker connects to the WebSocket endpoint. 2. The attacker sends a `navigate` action containing a loopback, private-network, link-local, or otherwise restricted URL. 3. Chromium requests the target from the browser host's network environment. 4. The attacker invokes `snapshot`, `screenshot`, or `evaluate` to retrieve the rendered response. 5. The attacker repeats the process to enumerate services or interact with internal administrative applications. Redirects can also be used to bypass validation if only the initial URL is checked. ### Impact Assessment The attacker may gain access to network resources available from the browser host, including: - Loopback-only administration interfaces. - Private intranet applications. - Development services and dashboards. - Router or infrastructure management pages. - Cloud metadata endpoints, depending on the environment. - Se ...[truncated 160 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only required protocols, normally `https:`. 2. Maintain an explicit allowlist of approved destination hostnames. 3. Resolve destination hostnames and reject loopback, private, link-local, multicast, reserved, and cloud metadata address ranges. 4. Revalidate the destination after every redirect. 5. Protect against DNS rebinding by validating resolved addresses at connection time. 6. Block unnecessary destination ports. 7. Use network-level egress controls to prevent Chromium from reaching internal management networks and metadata services. 8. Disable `snapshot`, `screenshot`, and script evaluation for untrusted destinations. 9. Record rejected navigation attempts without logging sensitive URL query values. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.js:20
Finding
Chromium Sandbox Disabled and Remote Debugging Interface Enabled<![CDATA[ ## Vulnerability Details **File Location**: `server.js:20-29` **Vulnerability Type**: Unsafe browser process configuration **Risk Level**: High ### Vulnerable Code ```js browser = await puppeteer.launch({ headless: false, // 显示界面,方便人工介入 args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--remote-debugging-port=9222' ] }); ``` ### Technical Analysis The browser is launched with both `--no-sandbox` and `--disable-setuid-sandbox`. These options disable important Chromium process-isolation mechanisms that normally limit the effect of a compromised renderer. The configuration also enables Chrome DevTools remote debugging on port `9222`. The debugging protocol provides extensive browser-control capabilities. The code does not configure authentication for this interface or demonstrate that network-level access is restricted. The service already controls Chromium through Puppeteer, so exposing an additional debugging port is unnecessary for its documented functionality. The combination of arbitrary navigation, disabled sandboxing, and an extra control interface substantially expands the attack surface. ### Attack Path A renderer-compromise path is: 1. An attacker uses the unrestricted navigation feature to load attacker-controlled content. 2. The content exploits a compatible Chromium renderer vulnerability. 3. Because Chromium sandboxing is disabled, the exploit encounters a weaker containment boundary. 4. The attacker may obtain privileges of the operating-system account running the browser. A debugging-interface path is: 1. An attacker reaches port `9222` if it is exposed by the host's binding and firewall configuration. 2. The attacker enumerates browser targets through the DevTools protocol. 3. The attacker attaches to a target and controls or inspects the browser without using the WebSocket service. ### Impact Assessment Successful exploitation may allow: - Control of ...[truncated 400 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox` and `--disable-setuid-sandbox`. 2. Run Chromium under a dedicated, unprivileged operating-system account. 3. Use container or operating-system sandboxing as an additional defense, not as a replacement for Chromium's sandbox. 4. Remove `--remote-debugging-port=9222` unless it is indispensable. 5. If debugging is required, bind it strictly to loopback and protect the host with firewall rules. 6. Run a currently supported Puppeteer and Chromium release and apply security updates promptly. 7. Restrict browser filesystem access, network egress, Linux capabilities, and writable directories. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.js:101
Finding
Sensitive Browser Action Parameters Are Written to Plaintext Logs<![CDATA[ ## Vulnerability Details **File Location**: `server.js:101-103` **Vulnerability Type**: Sensitive information exposure through logging **Risk Level**: High ### Vulnerable Code ```js ws.on('message', async (message) => { try { const { action, params, id } = JSON.parse(message); console.log(`⚡ 收到指令:${action}`, params); ``` The logged parameters can include text passed to the typing operation: ```js case 'type': if (!wsPage) throw new Error('没有活动的页面'); await wsPage.type(params.selector, params.text, { delay: params.delay || 50 }); return { success: true, action: 'type', target: params.selector, text: params.text }; ``` ### Technical Analysis The server logs the complete `params` object for every request. For the `type` action, that object contains the exact text entered into the selected form field. This may include passwords, one-time codes, personal information, private messages, unpublished content, or API tokens. The same logging operation records navigation URLs and arbitrary evaluation scripts, which may also contain secrets in query strings or source text. Console output is commonly retained by process managers, containers, CI systems, terminal recording, or centralized logging infrastructure. Sensitive information can therefore persist beyond the browser session and become available to users who have log access but should not have access to browser input. ### Attack Path 1. A legitimate user sends a `type` action containing sensitive text. 2. The service prints the complete parameter object to standard output. 3. A process manager, container runtime, or log collector stores the output. 4. An operator, attacker, or lower-privileged log reader retrieves the sensitive value. An attacker can also intentionally cause secrets to be logged if they can influence action parameters or automate sensitive browser workflows. ### Impact Assessment The vulnerability may expose: - Passwords and authentication codes. - ...[truncated 272 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not log complete request parameters. 2. Log only non-sensitive metadata such as the request ID, action name, result status, and duration. 3. Create a centralized redaction function that removes fields such as `text`, `script`, URL query strings, tokens, and authorization values. 4. Never return typed text in the action result. 5. Restrict access to application logs and configure short retention periods. 6. Disable verbose request logging in production. 7. Review and purge existing logs if the service has processed real credentials or confidential content. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.js:51
Finding
DOM Snapshot Discloses Current Form Field Values<![CDATA[ ## Vulnerability Details **File Location**: `server.js:51-60` **Vulnerability Type**: Sensitive information exposure **Risk Level**: High ### Vulnerable Code ```js case 'snapshot': if (!wsPage) throw new Error('没有活动的页面'); // 获取可交互的 DOM 结构简化版 const dom = await wsPage.evaluate(() => { return { title: document.title, url: document.location.href, inputs: Array.from(document.querySelectorAll('input, textarea')).map(i => ({ name: i.name, value: i.value })), links: Array.from(document.querySelectorAll('a')).slice(0, 20).map(a => ({ text: a.innerText, href: a.href })), buttons: Array.from(document.querySelectorAll('button, [role="button"]')).slice(0, 20).map(b => ({ text: b.innerText })) ``` ### Technical Analysis The snapshot operation enumerates every `input` and `textarea` element and returns its current `value`. It does not exclude password fields or fields marked as sensitive, and it does not require explicit permission to capture user-entered values. A DOM snapshot intended to describe page structure does not need to include raw field contents. Returning these values creates an unnecessary disclosure channel, particularly because the service is unauthenticated and all clients share the active page. Password controls may still expose their current value to script running in the same page context; visual masking does not prevent JavaScript from reading the value. ### Attack Path 1. A legitimate user enters credentials or confidential data into a web form. 2. Before the form is cleared or the page is closed, an attacker connects to the WebSocket service. 3. The attacker sends a `snapshot` action. 4. The page enumerates all input and textarea values. 5. The service returns those values to the attacker in the WebSocket response. ### Impact Assessment The attacker may retrieve: - Usernames and passwords currently present in form controls. - Personal and financial informa ...[truncated 236 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `value` property from the default snapshot response: ```js inputs: Array.from(document.querySelectorAll('input, textarea')) .map(i => ({ name: i.name, type: i.type, placeholder: i.placeholder })) ``` 2. Always redact password fields and fields with sensitive autocomplete values. 3. Treat all textarea contents as sensitive by default. 4. Require explicit, narrowly scoped authorization before returning any user-entered value. 5. Isolate browser pages and contexts per client. 6. Add response filtering to prevent accidental disclosure of tokens, credentials, and personal information. 7. Limit snapshot size and field count to reduce bulk data extraction. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The documented `evaluate` action enables arbitrary JavaScript execution in the page context, yet this high-risk capability is not prominently declared as such and is mixed with overstated claims about safety/features. In a browser-control skill, arbitrary script execution can manipulate authenticated sessions, extract page data, or perform unintended actions on behalf of the user.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented `evaluate` action enables arbitrary JavaScript execution in the page context, yet this high-risk capability is not prominently declared as such and is mixed with overstated claims about safety/features. In a browser-control skill, arbitrary script execution can manipulate authenticated sessions, extract page data, or perform unintended actions on behalf of the user.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The `evaluate` action allows any WebSocket client to supply arbitrary JavaScript that executes in the context of the currently loaded page. This exceeds the advertised browser-control scope and can be abused to read DOM contents, extract tokens or form data, trigger privileged in-page actions, and bypass any safer action-level restrictions the service otherwise provides.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This skill exposes browser automation functions that can navigate to sites, capture DOM content, and take screenshots, which may include sensitive user data, cookies-derived state, or internal application content. Without an explicit privacy and safety warning, users may unknowingly use it in contexts involving confidential or regulated data.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The `evaluate` action allows arbitrary JavaScript execution inside whatever page is currently open, including authenticated or sensitive web apps. This can alter page state, submit forms, extract page data, and abuse the user's browser session, making it materially dangerous if invoked by an untrusted caller or used without warning.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This JavaScript file uses Chinese exclusively in comments and console messages, including operational prompts to the user such as the login instruction. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation, and there is no indication that the skill is region-specific or offers a language choice.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a general-purpose browser automation skill providing navigation, clicking, input, screenshots, and DOM access via WebSocket. This file instead hard-codes navigation to a specific third-party site (`https://fanqie.baidu.com/writer`) and checks login state for a publishing workflow, which is narrower and materially different from the claimed generic browser-control behavior.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The service exposes browser automation features such as snapshot, screenshot, typing, clicking, and arbitrary page evaluation over an unauthenticated WebSocket interface, allowing page data and user-entered content to be collected and returned to the client without any consent prompt. In this skill context, the browser may access sensitive authenticated sessions, making silent data exfiltration materially more dangerous.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The natural-language content in the manifest description and README is entirely Chinese, and there is no indication that users may choose another language or that the skill is intended only for a Chinese-language audience. Under the stated policy, forcing a language without opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language description is written only in Chinese, which can impose a specific language/locale on users without offering a choice or documenting that the skill is region-specific. This matches the policy category for language or locale constraints lacking user opt-in.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"install-deps": "npm install puppeteer ws"
  },
  "dependencies": {
    "puppeteer": "^21.0.0",
    "ws": "^8.14.0"
  }
}
Confidence
88% confidence
Finding
Using a caret range for puppeteer allows installation of newer dependency versions that were not explicitly reviewed, which can introduce vulnerable or behavior-changing releases into the skill. In a browser-automation skill, dependency drift is more sensitive because Puppeteer controls a real browser and often processes untrusted web content, increasing the blast radius of a compromised or vulnerable package.

Unverifiable Dependency: puppeteer has 1 known advisory(ies) (CVE-2019-5786 (Use-After-Free in puppeteer)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
72% confidence
Finding
The manifest does not pin Puppeteer, so it is impossible to verify from this file alone whether the installed version includes fixes for known advisories. In this skill, that uncertainty matters more because Puppeteer drives a full Chromium instance and may interact with hostile pages, making browser-related vulnerabilities more consequential.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "puppeteer": "^21.0.0",
    "ws": "^8.14.0"
  }
}
Confidence
93% confidence
Finding
Using a caret range for ws permits unreviewed updates and makes the actual installed version environment-dependent, which is risky for a package that directly exposes WebSocket functionality. Because this skill's core feature is real-time browser control over WebSocket, any flaw in ws could affect the main attack surface and lead to denial of service, memory disclosure, or other network-exposed issues.

Unverifiable Dependency: ws has 7 known advisory(ies) (CVE-2016-10518 (Remote Memory Disclosure in ws); CVE-2024-37890 (ws affected by a DoS when handling a request with many HTTP headers); CVE-2026-45736 (ws: Uninitialized memory disclosure) +4 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The manifest leaves the exact ws version unverifiable while the package has a history of security advisories, so the deployment could resolve to an affected release without clear visibility. This is especially dangerous here because WebSocket communication is central to the skill's design, making ws part of the primary remotely reachable attack surface.

Description-Behavior Mismatch

Low
Confidence
76% confidence
Finding
The manifest emphasizes controlling a real browser over WebSocket and mentions screenshot capability, but this implementation persists the screenshot to a local file (`fanqie_status.png`). Saving artifacts to the local filesystem is an additional behavior beyond the described control interface and may matter for operator expectations.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The file-level description and operational log/error strings are written in Chinese, which effectively fixes the interaction language for operators reading logs and messages. The file does not offer any language choice or explain a justified region-specific requirement.

Static analysis

No suspicious patterns detected.