Back to skill

Security audit

Browser Steel

Security checks for vulnerabilities and agentic risk

Overview

This browser automation skill is coherent and not clearly malicious, but it deserves review because it can run an unpinned downloaded CLI and implicitly use local environment, cookie, profile, and session material.

Install only if you trust the Steel CLI source and are comfortable with broad browser automation. Prefer a preinstalled, pinned Steel CLI over the `npx` fallback, run it with a minimal environment, avoid placing unrelated secrets in workspace `.env` files, and provide cookie/profile/session inputs only for accounts and sites you are authorized to automate.

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/main.py:106
Finding
Unpinned npm Dependency Is Downloaded and Executed Automatically## Vulnerability Details **File Location**: `scripts/main.py`, lines 106-118 **Vulnerability Type**: Unpinned runtime dependency and mutable supply-chain execution **Risk Level**: Medium ### Vulnerable Code ```python if runtime == "node": if _command_exists("npx"): return ["npx", "--yes", "@steel-dev/cli"], "npx" raise SkillError("runtime=node requires `npx` (or set STEEL_BROWSER_CLI_BIN)") if runtime in ("auto", "cli"): if _command_exists("steel"): return ["steel"], "steel" if _command_exists("npx"): return ["npx", "--yes", "@steel-dev/cli"], "npx" raise SkillError("Steel CLI not found. Install `steel` or make `npx` available.") ``` ### Technical Analysis When a locally installed `steel` executable is unavailable, the default `auto` runtime falls back to: ```text npx --yes @steel-dev/cli ``` The package has no exact version or verified integrity value. Consequently, npm may download and immediately execute whichever package version the registry resolves at runtime. The `--yes` option removes the interactive installation confirmation. This creates a mutable execution path: the code ultimately executed can change after this skill has been reviewed. Although the referenced package name appears consistent with the intended Steel integration, the implementation does not constrain execution to an audited release. The child process inherits the merged environment passed by the wrapper. That environment may contain `STEEL_API_KEY` and other process credentials or configuration values. Therefore, a malicious or compromised dependency release could access those values with the privileges of the user running the skill. ### Attack Path 1. An attacker compromises the relevant npm package, its publisher account, or the package-distribution path and publishes a malicious release. 2. The target environment does not have a local `steel` executable, but it does have `npx ...[truncated 1325 chars]
Remediation
## Remediation Suggestions 1. Pin `@steel-dev/cli` to a reviewed exact version rather than resolving the latest available release: ```python return ["npx", "--yes", "@steel-dev/cli@X.Y.Z"], "npx" ``` 2. Prefer installing dependencies during a controlled setup phase instead of downloading executable code during normal skill operation. 3. Maintain a lockfile with integrity metadata and use a reproducible installation command such as `npm ci`. 4. Verify package provenance, signatures, and registry configuration where supported. 5. Remove the silent automatic fallback or require explicit user approval before downloading a missing executable dependency. 6. Execute the CLI with a minimal allowlisted environment rather than forwarding the entire process environment. Include only variables required by Steel. 7. Run browser automation in a sandbox or restricted account with limited filesystem and network access. 8. Establish a dependency update process in which new versions are reviewed and tested before changing the pinned release.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (22)

Ae1

High
Category
analysis-evasion
Content
- **`scripts/main.py`** = the wrapper that calls Steel CLI by default
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Chaining Abuse

High
Category
Tool Misuse
Content
CLI-first browser automation for Steel.
- Default runtime: Steel CLI (`steel` or `npx @steel-dev/cli`)
- Optional runtime: Python Playwright + Steel SDK plan runner
- Runtime choice: auto | cli | node | python
"""

from __future__ import print_function
Confidence
70% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR = Path(__file__).resolve().parents[1]
DEFAULT_ENV_CANDIDATES = [
    Path.cwd() / ".env",
    SKILL_DIR / ".env",
]
SUPPORTED_PYTHON_ACTIONS = [
Confidence
90% confidence
Finding
The skill is designed to look for a .env file in the current working directory, which often contains secrets such as API keys or session credentials. In an agent environment, automatic credential discovery from user workspaces materially increases the chance of unintended secret access and misuse.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR = Path(__file__).resolve().parents[1]
DEFAULT_ENV_CANDIDATES = [
    Path.cwd() / ".env",
    SKILL_DIR / ".env",
]
SUPPORTED_PYTHON_ACTIONS = [
    "goto",
Confidence
87% confidence
Finding
The skill also auto-loads a .env file from the skill directory, creating another implicit credential source. While somewhat more controlled than the working directory case, it still enables hidden secret consumption and behavior changes without clear user intent.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def _load_env(env_file=None):
    merged = dict(os.environ)
    chosen = None

    candidates = []
Confidence
93% confidence
Finding
Copying the full process environment into the skill gives it access to all ambient secrets, tokens, and configuration present in the parent context. In this skill, those values may then influence subprocess execution or remote browser connectivity, making broad environment harvesting more dangerous than in a simple standalone script.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell commands, reads environment variables, accesses files, and performs network operations, but it does not declare any explicit tool scope such as allowed-tools or permissions. That omission weakens least-privilege boundaries and can let an agent use broader capabilities than reviewers or platform policy expect, which is especially risky for a browser automation skill that can reach arbitrary URLs and handle session material.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using `npx @steel-dev/cli` without a pinned version introduces a supply-chain risk because execution may fetch the latest package at runtime. If the upstream package is compromised or a breaking release is published, the skill could execute unreviewed code in the agent environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
This runtime mode again specifies `npx @steel-dev/cli` without a pinned version, creating the same supply-chain exposure during tool resolution. In a skill that defaults to external browser automation and shell execution, unpinned remote package execution materially increases attack surface.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation explicitly enables proxy-backed and CAPTCHA-solving browser sessions without any guardrails, warnings, or policy constraints. In a browser automation skill, these capabilities can facilitate evasion of anti-bot controls and obscure request origin, increasing the risk of misuse against third-party sites or in ways that violate privacy, terms of service, or compliance obligations.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The documentation instructs the runtime to execute `npx --yes @steel-dev/cli` without pinning an exact version, which allows whatever package version is current at execution time to be fetched and run. In a browser automation skill, that creates a real supply-chain risk because the fetched CLI may gain new behavior, introduce malicious code, or change security properties while still being executed with the user's local permissions and access to browser/session data.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
This CLI-only mode explicitly falls back to `npx --yes @steel-dev/cli` with no version pin, so the skill may download and execute unreviewed code at runtime. Because the skill operates on live websites, sessions, cookies, and potentially credentials, an attacker controlling or compromising the package supply chain could exfiltrate sensitive data or execute arbitrary actions in the user's environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The `node` mode forces use of `npx --yes @steel-dev/cli` even when a local installed `steel` binary exists, increasing exposure to remote package resolution and execution. For a browser automation skill, forcing the network-fetched path makes the supply-chain risk more dangerous because the tool can access authenticated browser sessions, page contents, screenshots, and automation flows.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
Using 'npx --yes @steel-dev/cli' without a pinned version allows the fetched package version to vary over time. That creates a supply-chain risk where a compromised or unexpected upstream release can alter what code this skill executes.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_subprocess(command, env):
    completed = subprocess.run(
        command,
        env=env,
        stdout=subprocess.PIPE,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'command' from os.environ.get (line 448, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
def _run_subprocess(command, env):
    completed = subprocess.run(
        command,
        env=env,
        stdout=subprocess.PIPE,
Confidence
92% confidence
Finding
Although subprocess.run itself is used safely with a list, the command can be tainted by environment-controlled executable selection such as STEEL_BROWSER_CLI_BIN. Combined with automatic .env loading, a malicious local configuration can redirect execution to an arbitrary binary.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Content
for module_name in ("playwright", "steel"):
        try:
            __import__(module_name)
            report["current_modules"][module_name] = True
        except Exception:
            report["current_modules"][module_name] = False
Confidence
75% confidence
Finding
Dynamic __import__() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return None

    command = [str(target)] + sys.argv
    return subprocess.call(command, env=env)


async def _run_python_plan_async(args, env):
Confidence
95% confidence
Finding
The re-exec path invokes a Python interpreter taken from STEEL_BROWSER_PYTHON_BIN, which can come from the environment or loaded .env file. That gives an attacker who can influence configuration a direct arbitrary-code-execution primitive by pointing to a malicious executable, and this skill explicitly auto-loads local .env files, increasing exposure.

Tainted flow: 'command' from os.environ.get (line 448, credential/environment) → subprocess.call (code execution)

Medium
Category
Data Flow
Content
return None

    command = [str(target)] + sys.argv
    return subprocess.call(command, env=env)


async def _run_python_plan_async(args, env):
Confidence
97% confidence
Finding
The command is built from STEEL_BROWSER_PYTHON_BIN and then executed, creating a straightforward tainted flow from environment/configuration to code execution. Because the skill auto-loads .env files from the working directory and skill directory, this becomes a practical local execution risk.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The API key is interpolated directly into a WebSocket connection URL for a remote service. While this may be required by the SDK protocol, embedding secrets in URLs increases accidental leakage risk through logs, error messages, telemetry, or debugging output.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
Cookie data is loaded from a local file into the browser context and then used against potentially remote sites, effectively importing authentication material into automated browsing. In an agent skill, that can silently reuse sensitive sessions and enable account access or data extraction without clear user awareness.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The generic browser passthrough exposes arbitrary Steel CLI browser subcommands rather than a narrow, declared set of workflows. In an agent setting, that broadens capability beyond expected boundaries and can enable unsafe actions or data access paths not reviewed in the skill manifest.

Context-Inappropriate Capability

Low
Confidence
94% confidence
Finding
The skill automatically searches for and loads arbitrary local .env files, merging their contents into the execution environment. That expands scope from browser automation into local secret ingestion and configuration-based behavior control, which is risky in an agent context.

Static analysis

No suspicious patterns detected.