Back to skill

Security audit

Fox Chrome Devtools Mcp

Security checks for vulnerabilities and agentic risk

Overview

This is a real Chrome browser automation integration, but it needs Review because it runs a mutable external package with broad browser-control authority.

Install only if you are comfortable with a browser-control MCP server and can pin or preinstall a reviewed chrome-devtools-mcp version. Avoid using it on sensitive logged-in sessions, financial/admin workflows, or production sites unless you explicitly authorize each action and understand that page content and browser actions may be exposed to the agent/server.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (1)

T08 · Insecure Dependencies

Warning
Location
scripts/setup_chrome_mcp.py:39
Finding
Unpinned npm Package Is Automatically Downloaded and Executed<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_chrome_mcp.py:39`, `scripts/setup_chrome_mcp.py:68-76`, `scripts/setup_chrome_mcp.py:124-128`; documented in `SKILL.md:36-53` and `SKILL.md:60-68` **Vulnerability Type**: Unpinned executable third-party dependency **Risk Level**: Medium ### Vulnerable Code The setup operation downloads and executes the mutable `latest` release: ```python # Pre-cache the package print("📦 Installing chrome-devtools-mcp...") code, out, err = run("npx -y chrome-devtools-mcp@latest --help", timeout=60) ``` The generated OpenClaw configuration also uses the mutable release: ```python config = { "mcp": { "servers": { "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest", "--headless", "--no-usage-statistics"] } } } } ``` The test operation downloads and launches the same unpinned package: ```python proc = subprocess.Popen( ["npx", "-y", "chrome-devtools-mcp@latest", "--headless", "--no-usage-statistics"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) ``` The documentation instructs users to use the same pattern: ```bash npx -y chrome-devtools-mcp@latest --help ``` ```json { "mcp": { "servers": { "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest", "--headless", "--no-usage-statistics"] } } } } ``` ### Technical Analysis The `latest` npm distribution tag is mutable and can resolve to a different package version each time the command runs. The `-y` option suppresses the interactive installation confirmation, while `npx` downloads and immediately executes the resolved package. Consequently, the effective code executed by this Skill is not fixed to the version that was reviewed. A future upstream release, compromised publisher account, registry compromise, or malicious supply-chain update could replace the re ...[truncated 1904 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `chrome-devtools-mcp@latest` with an exact, reviewed version in every command and generated configuration, for example: ```python CHROME_DEVTOOLS_MCP_VERSION = "x.y.z" package = f"chrome-devtools-mcp@{CHROME_DEVTOOLS_MCP_VERSION}" ``` 2. Do not use version ranges, mutable distribution tags, or implicit latest-version resolution. 3. Prefer a project-local installation governed by a committed lockfile rather than downloading the package whenever the server starts: ```bash npm install --save-exact chrome-devtools-mcp@x.y.z npm ci ``` 4. Commit and review `package.json` and `package-lock.json`, and use `npm ci` so dependency resolution follows the lockfile exactly. 5. Verify registry integrity metadata and package provenance where supported. Consider enforcing an approved registry and allowlisting the expected package and version. 6. Separate dependency installation from routine MCP startup. Startup should execute an already installed, verified binary and should not retrieve new executable code. 7. Remove `-y` from any workflow that can unexpectedly install a package, or require explicit administrative approval before downloading a new version. 8. Update `SKILL.md`, the setup operation, the test operation, and the generated OpenClaw configuration together so none of them continue recommending or executing `@latest`. 9. Establish an explicit upgrade process that includes source review, release-note review, integrity verification, and testing before changing the pinned version. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description claims the skill is the Chrome DevTools MCP server used to control Chrome and perform browser automation/testing tasks. However, this code chunk does not implement those browser-control capabilities. Instead, it acts as an installer/status checker/test harness for the external chrome-devtools-mcp package. It checks local dependencies, searches for Chrome binaries, prints configuration for openclaw.json, reads ~/.openclaw/openclaw.json to inspect MCP configuration, and briefly launches the MCP server process to see if it starts. That is a materially different primary purpose from being the automation server itself. While these behaviors are related support tooling, the declared description specifically represents the skill as the browser automation/testing server, which this code chunk is not.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def run(cmd, capture=True, timeout=30):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=capture, text=True, timeout=timeout)
        return r.returncode, r.stdout.strip() if capture else "", r.stderr.strip() if capture else ""
    except subprocess.TimeoutExpired:
        return 1, "", "timeout"
Confidence
96% confidence
Finding
Using shell=True in a reusable command wrapper is dangerous because it turns any caller-provided string into a shell command, enabling metacharacter expansion, chaining, redirection, and environment/PATH manipulation. In an agent skill setup script, this becomes more sensitive because such scripts are often run in semi-automated environments where future modifications may pass external input into the wrapper.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill documents shell-based installation and execution of an MCP server but does not declare any explicit tool scope or allowed-tools restrictions. In an agent environment, undeclared shell capability increases the chance that the skill can be invoked with broader-than-expected execution privileges, reducing policy enforceability and auditability.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The description is broad enough to encourage invocation in many contexts without clear constraints, while the underlying capability grants full browser control. In an agent setting, vague triggering language can lead to overuse on live sites, authenticated sessions, or sensitive internal applications where automated clicks, form fills, and script execution are high-risk.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill advertises powerful browser actions—clicking, form filling, file upload, script execution, and dialog handling—but does not clearly warn that these actions can modify live accounts, submit transactions, change settings, or leak session-bound data. Because the context is full browser automation, missing safety guidance materially increases the chance of destructive or privacy-impacting misuse.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
Using npx with @latest causes the skill to fetch and execute whatever package version is current at runtime, which creates a supply-chain risk and defeats reproducibility. If the upstream package or one of its dependencies is compromised, the agent could execute attacker-controlled code immediately during installation or launch.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
This invocation also relies on @latest, meaning the executed code can change over time without review. In an automated agent workflow, dynamic package resolution materially increases the risk of remote code execution through a malicious or newly vulnerable upstream release.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
Connecting to an existing browser does not reduce the package execution risk introduced by npx @latest; the package itself is still fetched and run dynamically. That creates a persistent supply-chain exposure in addition to the browser-control capability described by the skill.

Rp1

Medium
Category
MCP Rug Pull
Confidence
98% confidence
Finding
The OpenClaw integration example embeds npx @latest directly into persistent configuration, which normalizes repeated execution of unpinned remote code. This is especially risky because MCP servers typically run with broad automation powers and may access browser sessions, page content, and local resources exposed to the agent.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(cmd, capture=True, timeout=30):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=capture, text=True, timeout=timeout)
        return r.returncode, r.stdout.strip() if capture else "", r.stderr.strip() if capture else ""
    except subprocess.TimeoutExpired:
        return 1, "", "timeout"
Confidence
94% confidence
Finding
The helper uses subprocess.run with shell=True on arbitrary command strings. Even though current call sites are hardcoded, this pattern creates a command-injection sink: any future use with user-controlled or config-derived input could execute unintended shell metacharacters, and shell resolution also broadens PATH-based hijack risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
99% confidence
Finding
The script executes 'npx -y chrome-devtools-mcp@latest --help', which fetches and runs the latest package version at setup time. Using @latest creates a supply-chain risk: a compromised upstream release, typo-squatted dependency path, or unexpected breaking change would be executed immediately on the host.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Try starting with --headless
    print("Starting MCP server (headless)...")
    proc = subprocess.Popen(
        ["npx", "-y", "chrome-devtools-mcp@latest", "--headless", "--no-usage-statistics"],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.