Back to skill

Security audit

Remote Relay

Security checks for vulnerabilities and agentic risk

Overview

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

Install only if you trust the relay operator and can enforce wss:// configuration yourself. Before using this in production, the maintainer should reject plaintext ws:// URLs and enforce authenticated online state before accepting prompt, workflow, status, or restart commands.

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:87
Finding

Operational Commands Are Accepted Before Relay Authentication Completes

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
config.ts:7
Finding

Plaintext WebSocket Configuration Exposes Credentials and Remote-Control Traffic

Content
View full analysis
): RemoteRelayConfig { if (!config.relay_url) throw new Error("remote-relay: relay_url is required"); if (!config.node_id) throw new Error("remote-relay: node_id is required"); if (!config.auth_token) throw new Error("remote-relay: 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 also explicitly accepted by the test at `config.test.ts:18-21`: ```ts it("converts http to ws", () => { const result = validateConfig({ ...valid, relay_url: "http://localhost:8080" }); expect(result.relay_url).toBe("ws://localhost:8080"); }); ``` ### Technical Analysis The validator converts `http://` URLs into plaintext `ws://` URLs and does not reject an explicitly supplied `ws://` URL. Despite the comment stating that the function ensures secure connections, no requirement that the final protocol be `wss:` is enforced. The WebSocket carries highly sensitive data: - The authentication token and node identifier in the `hello` message. - Remote prompts and streamed responses. - Workflow identifiers and parameters. - Runtime status and last-error information. - Restart commands. When `ws://` is used, these values have no transport confidentiality or integrity. A network-positioned attacker can observe the authentication token and application data or modify the bidirectional command stream. This behavior contradicts the TLS-only guarantees in `README.md` and `SKILL.md`. The implementati ...[truncated 1732 chars]
Remediation
View remediation
): RemoteRelayConfig { if (!config.relay_url) { throw new Error("remote-relay: relay_url is required"); } if (!config.node_id) { throw new Error("remote-relay: node_id is required"); } if (!config.auth_token) { throw new Error("remote-relay: auth_token is required"); } let parsed: URL; try { parsed = new URL(config.relay_url); } catch { throw new Error("remote-relay: relay_url must be a valid URL"); } if (parsed.protocol === "https:") { parsed.protocol = "wss:"; } if (parsed.protocol !== "wss:") { throw new Error("remote-relay: relay_url must use wss://"); } if (parsed.username || parsed.password) { throw new Error( "remote-relay: relay_url must not contain embedded credentials" ); } parsed.pathname = parsed.pathname.replace(/\/+$/, ""); return { relay_url: parsed.toString().replace(/\/$/, ""), node_id: config.node_id, auth_token: config.auth_token, }; } ``` Additional hardening should include: 1. Remove the test that treats conversion to `ws://` as valid and replace it with tests requiring rejection of `http://` and `ws://`. 2. Reject unsupported protocols and malformed URLs explicitly. 3. If plaintext localhost communication is essential for development, require a clearly named development-only opt-in that defaults to disabled and rejects non-loopback hosts. 4. Keep TLS certificate validation enabled and avoid options that accept self-signed or invalid certificates in production. 5. Rotate authentication tokens that may previously have been transmitted through plaintext WebSocket connections. 6. Update documentation so transport guarantees exactly match enforced runtime behavior. 7. Consider short-lived, node-bound tokens to limit the impact of credential in ...[truncated 17 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 (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared description frames the skill as a secure outbound-only relay and emphasizes what it does not expose (ports, SSH, Telegram), but the actual code chunk shows a remote control protocol and runtime contract with significant control capabilities. Incoming messages include prompt, workflow, status, and restart types, and the runtime must support executing prompts, executing workflows, returning runtime state, and restarting OpenClaw. These are substantive remote administration capabilities not clearly disclosed in the description. While the code does not contradict the 'no exposed ports, no SSH, no Telegram' claims, it materially expands the skill’s functional purpose beyond a generic relay into an active remote execution and restart mechanism.

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
88% confidence
Finding

On connection, the client sends the configured auth token to the relay as part of the hello message. Although this is likely functionally necessary, the file lacks any user-facing disclosure or comment warning that credentials are transmitted to an external endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code executes a remotely received prompt and streams generated token content back over the WebSocket relay. While the file logs connection and authentication events, it does not provide a user-facing warning or confirmation that prompt contents and model output will be transmitted to a remote service.

Content

No source excerpt is available for this finding.