T08 · Insecure Dependencies
- Location
scripts/setup_chrome_mcp.py:39- Finding
Unpinned Remote npm Package Download and Execution
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears purpose-aligned, but it gives agents powerful browser control while repeatedly downloading and running an unpinned npm package, so it should be reviewed before installation.
Install only if you are comfortable giving an agent control over a Chrome session. Prefer a pinned, reviewed chrome-devtools-mcp version instead of @latest, run it in an isolated browser profile or container, avoid logged-in or sensitive browsing sessions, and disable telemetry/CrUX features when privacy matters.
scripts/setup_chrome_mcp.py:39Unpinned Remote npm Package Download and Execution
Using shell=True in a reusable command runner is dangerous because any future non-constant input passed into cmd can become shell syntax and execute unintended commands. In a setup utility for developer tooling, this is especially risky because the script is intended to run on user workstations with meaningful local privileges and access to environment variables, files, and credentials.
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"
The skill exposes shell execution pathways through setup and launch commands but does not declare any tool scope restrictions such as permissions or allowed-tools. In an agent environment, this increases the chance that the skill can invoke broader command execution than reviewers or users expect, especially given it launches a browser automation server with powerful local capabilities.
Using an unpinned package reference allows the installed MCP server version to change over time, including pulling compromised, malicious, or breaking releases at execution time. Because this skill grants browser control and can interact with local files, network requests, and page scripting, a supply-chain compromise could lead to significant agent or host impact.
The command starts the MCP server from the latest available package rather than a vetted fixed release. This creates a supply-chain risk where future upstream changes or a compromised publication could execute arbitrary code in the environment when the skill is run.
Connecting to an existing browser with an unpinned MCP package still relies on fetching and executing whatever package version is current at runtime. Since the tool can inspect traffic, run page JavaScript, and automate browser actions, any malicious update would have broad access within the browsing session.
The OpenClaw integration example instructs users to configure chrome-devtools-mcp@latest, causing every deployment to trust the newest registry version automatically. In a long-lived agent platform, this is especially dangerous because the MCP server has extensive browser automation and observation capabilities, magnifying the impact of a compromised release.
The helper wraps subprocess.run with shell=True, which executes the provided string through the shell. Although current call sites use hardcoded commands, this utility makes future or indirect command injection far easier, and also exposes execution to PATH manipulation and shell metacharacter interpretation.
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"
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.
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.
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.
The script executes chrome-devtools-mcp@latest via npx, which fetches and runs whatever package version is current at execution time. That creates a real supply-chain risk: a compromised upstream package or breaking change could lead to arbitrary code execution on the host during setup.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# 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
)