Back to skill

Security audit

Private Bridge

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed remote-control relay, but its implementation weakens the promised security around authentication and encrypted transport.

Review this carefully before installing. Use it only with a relay operator you trust, require a wss:// relay URL, avoid plaintext ws:// or http:// configuration, treat AUTH_TOKEN as a remote-control credential, and prefer a version that gates commands on successful authentication and restricts which workflows can be triggered remotely.

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 (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
relayClient.ts:64
Finding

Privileged Relay Commands Are Processed Before Authentication

Content
View full analysis
{ try { const msg = JSON.parse(String(event.data)); this.handleMessage(msg); } catch { console.error("[private-bridge] Invalid message received"); } }; private handleMessage(msg: { type: string; data?: unknown }): void { switch (msg.type) { case "hello_ok": console.log("[private-bridge] Authenticated"); this.backoff = INITIAL_BACKOFF; this.connectionState = "online"; this.startHeartbeat(); break; case "prompt": case "status": case "restart": case "workflow": this.dispatch(msg as { type: string; data: IncomingMessage }); break; case "error": console.error("[private-bridge] Relay error:", msg.data); break; default: console.warn(`[private-bridge] Rejecting unknown type: ${msg.type}`); break; } } ``` ### Technical Analysis The client marks the connection as authenticated only after receiving `hello_ok`, but command dispatch does not verify that `connectionState` is `online` or that authentication has completed. Consequently, recognized command messages are passed to `dispatch()` immediately, including while the client is still in the `reconnecting` state and before the relay has accepted the authentication token. The affected commands invoke sensitive runtime capabilities: - `prompt` invokes `runtime.executePrompt()`. - `workflow` invokes `runtime.executeWorkflow()` with relay-controlled identifiers and parameters. - `status` discloses runtime health information. - `restart` invokes `runtime.restart()`. This contradicts the documented guarantee that relay commands are accepted only while the node is authenticated and online. Transport-level connection establishment is not equivalent to application-level authentication ...[truncated 1526 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
config.ts:7
Finding

Plaintext WebSocket Configuration Exposes Authentication Tokens and Remote-Control Traffic

Content
View full analysis
): RemoteRelayConfig { if (!config.relay_url) throw new Error("private-bridge: relay_url is required"); if (!config.node_id) throw new Error("private-bridge: node_id is required"); if (!config.auth_token) throw new Error("private-bridge: auth_token is required"); // Normalize URL: ensure wss:// for secure connections let url = config.relay_url.replace(/\/+$/, ""); url = url.replace(/^https:\/\//, "wss://"); url = url.replace(/^http:\/\//, "ws://"); return { relay_url: url, node_id: config.node_id, auth_token: config.auth_token, }; } ``` The insecure behavior is explicitly expected by `config.test.ts:18-20`: ```ts it("converts http to ws", () => { const result = validateConfig({ ...valid, relay_url: "http://localhost:8080" }); expect(result.relay_url).toBe("ws://localhost:8080"); }); ``` The token is subsequently sent over the configured connection in `relayClient.ts:52-61`: ```ts this.ws.onopen = () => { console.log("[private-bridge] Connected, sending auth"); this.send({ type: "hello", data: { node_id: this.config.node_id, token: this.config.auth_token, meta: { kind: "openclaw" }, }, }); }; ``` ### Technical Analysis Configuration validation deliberately converts `http://` relay URLs to `ws://`, permitting an unencrypted WebSocket connection. The initial application handshake sends the authentication token and node identifier over this channel. Subsequent traffic can include remote prompts, model response tokens, workflow parameters and results, health information, error details, and process-restart commands. A plaintext WebSocket provides neither confidentiality nor transport integrity. An attacker with a suitable network position ...[truncated 2168 chars]
Remediation
View remediation
): RemoteRelayConfig { if (!config.relay_url) { throw new Error("private-bridge: relay_url is required"); } if (!config.node_id) { throw new Error("private-bridge: node_id is required"); } if (!config.auth_token) { throw new Error("private-bridge: auth_token is required"); } const normalized = config.relay_url.startsWith("https://") ? config.relay_url.replace(/^https:/, "wss:") : config.relay_url; const relayUrl = new URL(normalized); if (relayUrl.protocol !== "wss:") { throw new Error("private-bridge: relay_url must use wss://"); } if (relayUrl.username || relayUrl.password) { throw new Error("private-bridge: embedded URL credentials are not allowed"); } relayUrl.pathname = relayUrl.pathname.replace(/\/+$/, ""); return { relay_url: relayUrl.toString().replace(/\/$/, ""), node_id: config.node_id, auth_token: config.auth_token, }; ...[truncated 9 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents the skill as a secure outbound-only relay for remote OpenClaw control, but the supplied code shows concrete remote-control capabilities beyond a generic relay transport description. Specifically, it supports inbound command types for prompt execution, workflow execution, status queries, and restart actions, and requires the host runtime to implement executePrompt, executeWorkflow, and restart. It also defines outbound telemetry/status structures including uptime, active task count, last error, and connection state. While this is broadly related to remote control, the description omits these sensitive operational capabilities, especially remote prompt execution and restart control. The snippet does not mention SSH or Telegram, so those parts are neither confirmed nor contradicted here, but the undeclared command-and-control functionality is significant enough to constitute a mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
files: ["relayClient.ts", "config.ts", "capabilities.ts", "index.ts"]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code opens a WebSocket connection and sends identifying information and an auth token in the hello message. It also later transmits prompt output and heartbeat/status data, but the file only includes developer logs and brief method comments, not any user-facing disclosure or warning about network transmission of potentially sensitive data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The client accepts authenticated remote messages that can directly trigger restart and arbitrary workflow execution via runtime.restart() and runtime.executeWorkflow() with no local authorization, confirmation, allowlist, or capability checks visible in this file. In the context of a remote-control relay for OpenClaw, this meaningfully expands the attack surface: compromise of the relay, token theft, or misrouting of messages could result in remote service disruption or execution of sensitive automated actions.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest identifies this skill as "remote-relay", but the init() docstring says it initializes the "PrivateBridge skill." This is an active documentation mismatch that can mislead integrators about what component they are invoking, even though the code itself constructs a RelayClient.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.