Back to skill

Security audit

Plasmate

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent web-browsing purpose, but its installer and helper script can execute unverified remote code and change the local environment without enough scoping.

Review before installing. Prefer a pinned, signed, or checksum-verified Plasmate release instead of the curl-to-shell installer, and run the helper in an isolated environment with dependencies installed ahead of time. Keep AWP connections on 127.0.0.1 unless you explicitly trust the server and network, and avoid typing secrets or account-changing actions through this skill without separate confirmation.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:20
Finding

Unverified Remote Installer Is Piped Directly Into a Shell

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:20-29 and SKILL.md:45-51
Vulnerability Type: Remote payload retrieval and arbitrary code execution
Risk Level: High

Complete Code Snippet:

json
{
  "id": "shell",
  "kind": "shell",
  "command": "curl -fsSL https://plasmate.app/install.sh | sh",
  "bins": ["plasmate"],
  "label": "Install Plasmate (pre-built binary)"
}
bash
# Build from source (recommended)
cargo install plasmate

# Or use the install script
curl -fsSL https://plasmate.app/install.sh | sh

Technical Analysis

The installation instructions download a mutable script from an external server and pass its response directly to sh. The downloaded content is not displayed for inspection, pinned to a specific release, checked against a cryptographic digest, or verified with a trusted signing key.

Although HTTPS protects the connection under normal circumstances, it does not establish that every future response from the domain is safe. The effective code executed by this Skill can change after the package has been audited. A compromise of the website, hosting account, deployment pipeline, DNS infrastructure, TLS credentials, or installer publishing process could therefore convert the installation command into an arbitrary-code execution channel.

This behavior is not required for the declared web-browsing functionality. The document already provides cargo install plasmate as a source-build alternative. Even that alternative should ideally be version-pinned, but it avoids directly interpreting a mutable HTTP response as shell code.

Attack Path

  1. An attacker compromises or gains publishing control over https://plasmate.app/install.sh, or redirects traffic through compromised infrastructure.
  2. The attacker modifies the installer response to include arbitrary shell commands.
  3. A user or agent follows the documented installation command.
  4. curl ret ...[truncated 951 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove all curl | sh installation instructions and automated metadata entries.
  2. Publish immutable, versioned release artifacts instead of relying on a mutable installer endpoint.
  3. Download the selected artifact as a separate step and verify a SHA-256 or stronger digest obtained through a trusted, independently protected channel.
  4. Prefer signed releases and validate signatures against a pinned project signing key.
  5. Pin the exact Plasmate version rather than installing an unspecified latest release.
  6. If a shell installer must remain available, instruct users to download and inspect it before execution; this is weaker than signed artifacts and should not replace signature verification.
  7. Do not recommend elevated execution unless a documented operation strictly requires it.

T08 · Insecure Dependencies

Warning
Location
scripts/awp-browse.py:20
Finding

Missing Python Dependency Is Installed Automatically Without Version or Integrity Pinning

Content
View full analysis

Vulnerability Details

File Location: scripts/awp-browse.py:20-25
Vulnerability Type: Unsafe runtime dependency installation
Risk Level: Medium

Complete Code Snippet:

python
try:
    import websockets
except ImportError:
    print("Installing websockets...", file=sys.stderr)
    subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "websockets"])
    import websockets

Technical Analysis

Running the browser client automatically invokes pip when websockets is unavailable. The package has no pinned version, no locked transitive dependency graph, and no required package hash. Pip may also use package indexes or mirrors configured through command-line defaults, environment variables, or user-level configuration.

Consequently, the installed code is determined at runtime rather than during review. A compromised package release, package index, configured mirror, dependency, or local pip configuration could cause untrusted code to be installed and imported. Automatic environment modification is also an unexpected side effect for a browsing helper and exceeds the minimum behavior needed to communicate with the local server.

The use of a list-based subprocess invocation prevents shell metacharacter injection in this particular call, but it does not address dependency provenance or integrity.

Attack Path

  1. The websockets module is absent from the active Python environment.
  2. An attacker compromises the selected package source, a relevant package release, a dependency, or a pip mirror configured for the environment.
  3. The user invokes awp-browse.py.
  4. The script silently requests the current unpinned websockets distribution from that source.
  5. Pip installs the selected package and any dependencies into the active environment.
  6. The script imports the installed module, executing its import-time Python code in the current process.
  7. Malicious package code co ...[truncated 679 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove runtime calls to pip from the application.
  2. Declare websockets as an explicit project dependency and require users to install dependencies before execution.
  3. Pin an reviewed version and lock all transitive dependencies.
  4. Use hash-checked installation, such as a requirements file containing exact versions and --hash entries with pip --require-hashes.
  5. Install dependencies inside a dedicated virtual environment rather than modifying a shared interpreter.
  6. Document the expected package index and avoid inheriting untrusted mirror configuration in automated deployments.
  7. Fail safely with a clear dependency-installation message when the import is unavailable.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/awp-browse.py:29
Finding

Remote AWP Connections Can Transmit Browsing and Form Data Over Plaintext WebSockets

Content
View full analysis

Vulnerability Details

File Location: scripts/awp-browse.py:29-42 and scripts/awp-browse.py:143-174
Vulnerability Type: Plaintext transmission of potentially sensitive data and unenforced local trust boundary
Risk Level: Medium

Complete Code Snippet:

python
class AWPClient:
    def __init__(self, host: str = "127.0.0.1", port: int = 9222):
        self.url = f"ws://{host}:{port}"
        self.ws = None
        self._pending = {}

    async def connect(self):
        self.ws = await websockets.connect(self.url)
        asyncio.create_task(self._reader())
        return await self._request("awp.hello", {
            "client_name": "openclaw-plasmate-skill",
            "client_version": "0.1.0",
            "awp_version": "0.1"
        })
python
parser.add_argument("--text", help="Text to type")
parser.add_argument("--direction", choices=["up", "down"], default="down", help="Scroll direction")
parser.add_argument("--port", type=int, default=9222, help="Plasmate server port")
parser.add_argument("--host", default="127.0.0.1", help="Plasmate server host")
args = parser.parse_args()

ensure_server(args.port)

client = AWPClient(args.host, args.port)
try:
    await client.connect()
    session_id = await client.create_session()

    await client.navigate(session_id, args.url)

    if args.action == "navigate":
        result = await client.snapshot(session_id)
    elif args.action == "click":
        await client.click(session_id, args.ref)
        result = await client.snapshot(session_id)
    elif args.action == "type":
        await client.type_text(session_id, args.ref, args.text)
        result = await client.snapshot(session_id)

The corresponding type request sends user-provided text as follows:

python
async def type_text(self, session_id: str, ref: str, text: str):
    return await self._request("act.type", {
        "session_id"
...[truncated 2530 chars]
Remediation
View remediation

Remediation Suggestions

  1. If the intended architecture is local-only, remove --host and hard-code a validated loopback destination.
  2. Validate resolved addresses, not only the host string, and reject non-loopback IPv4 and IPv6 destinations.
  3. If remote operation is required, use authenticated wss:// connections with strict certificate and hostname validation.
  4. Add explicit server authentication, such as a securely managed token or mutually authenticated TLS.
  5. Clearly disclose that URLs, page data, interaction metadata, and typed text are sent to the configured server.
  6. Require explicit user confirmation before transmitting likely secrets or form credentials to a non-local endpoint.
  7. Update the privacy statement so that it accurately distinguishes default local operation from optional remote operation.
  8. Consider restricting allowed remote endpoints through an explicit configuration allowlist.
Vulnerability Patterns
  • 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (11)

External Script Fetching

High
Category
Supply Chain
Confidence
99% confidence
Finding

The metadata includes an installer command that fetches a remote script and executes it via the shell. Because this is embedded in skill install metadata, users or automation may run it with little scrutiny, creating a direct remote code execution path if the fetched content changes or is tampered with.

Content

Scanner excerpt · SKILL.md (reported line 26)May include surrounding context.

md
{
              "id": "shell",
              "kind": "shell",
              "command": "curl -fsSL https://plasmate.app/install.sh | sh",
              "bins": ["plasmate"],
              "label": "Install Plasmate (pre-built binary)",
            },

External Script Fetching

High
Category
Supply Chain
Confidence
99% confidence
Finding

The documentation repeats a direct remote-script execution command, normalizing unsafe installation behavior. This is dangerous because readers may copy-paste it into privileged shells, allowing arbitrary code execution from a mutable remote endpoint.

Content

Scanner excerpt · SKILL.md (reported line 50)May include surrounding context.

cargo install plasmate

Or use the install script

curl -fsSL https://plasmate.app/install.sh | sh

text

## Protocols

Chaining Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The shell pipe into sh is a classic command-chaining anti-pattern that removes the opportunity to inspect the downloaded content before execution. In this skill's context, it is especially risky because the project is explicitly aimed at agent workflows, where automation may amplify unsafe copy-paste or scripted execution.

Content

Scanner excerpt · SKILL.md (reported line 50)May include surrounding context.

cargo install plasmate

Or use the install script

curl -fsSL https://plasmate.app/install.sh | sh

text

## Protocols

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill exposes shell-based installation and local server/browser capabilities but does not declare any explicit tool scope or permissions boundaries. That increases the chance an agent framework grants broader-than-necessary execution rights, making misuse or unintended command execution harder to contain.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The installation instructions tell users to pipe a remotely fetched script directly into the shell without any integrity verification or warning. If the hosting site, CDN, DNS, TLS trust chain, or script publisher is compromised, arbitrary code will execute immediately on the user's machine.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script silently installs missing dependencies during execution, which changes the host environment and executes externally sourced code. In an agent skill context, that is more dangerous because a nominal web-browsing tool gains package-management behavior that users may not expect or authorize.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
93% confidence
Finding

Installing a Python package at runtime executes package-management operations in the current environment and pulls code from an external repository without pinning or prior approval. That creates a supply-chain risk and gives the script software installation capability beyond its stated browsing role.

Content

Scanner excerpt · scripts/awp-browse.py (reported line 27)May include surrounding context.

python
import websockets
except ImportError:
    print("Installing websockets...", file=sys.stderr)
    subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "websockets"])
    import websockets

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The click and type methods enable state-changing browser actions such as submitting forms, sending messages, or interacting with authenticated sessions without any confirmation or policy guardrails. In an agent context, this increases the risk of unintended transactions or misuse if higher-level controls are absent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest says the skill browses the web via Plasmate, but this code also manages local process lifecycle by starting plasmate serve when the port is closed. Launching background processes is a separate host-control capability that is not clearly justified by the stated purpose alone.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/awp-browse.py (reported line 126)May include surrounding context.

python
pass

    print(f"Starting Plasmate on port {port}...", file=sys.stderr)
    subprocess.Popen(
        ["plasmate", "serve", "--protocol", "awp", "--port", str(port)],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

If the server is not running, the script silently starts an external plasmate serve process via subprocess.Popen. Although there is a brief stderr message when launching, the usage/help text does not clearly warn users that invoking the script may start a background local service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.