Back to skill

Security audit

Approve new channels, and connections to openclaw ui and terminal

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed OpenClaw approvals dashboard, but it exposes high-impact pairing data and a host terminal through under-protected web/socket paths.

Review carefully before installing. Only run this on a trusted machine and do not expose the port beyond localhost. Change all defaults first, but note that changing passwords alone does not fix the unauthenticated Socket.IO terminal/data exposure, token-in-page exposure, or XSS-prone rendering. The terminal feature and gateway-token copy flow should be removed or strongly reworked before use with real OpenClaw credentials.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:600
Finding

Unauthenticated Socket.IO Events Provide Arbitrary Host Shell Access

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:569
Finding

Unauthenticated Socket.IO Connections Receive Sensitive Pairing and Device Records

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
templates/channel_approvals.html:463
Finding

Stored Cross-Site Scripting Through Pairing and Device Metadata

Content
View full analysis
Channel${pairing.channel_id}`; contentDiv.appendChild(field); } if (pairing.code) { const field = document.createElement('div'); field.className = 'pairing-field'; field.innerHTML = `Code${pairing.code}`; contentDiv.appendChild(field); } if (pairing.user_id) { const field = document.createElement('div'); field.className = 'pairing-field'; field.innerHTML = `User ID${pairing.user_id}`; contentDiv.appendChild(field); } if (pairing.device_name) { const field = document.createElement('div'); field.className = 'pairing-field'; field.innerHTML = `Device${pairing.device_name}`; contentDiv.appendChild(field); } ``` Device records are rendered similarly: ```javascript container.innerHTML = items.map(item => `
${platformIcon(item.platform)} ${item.platform || 'Unknown'} — ${item.clientMode || item.clientId || 'device'}
🌐 ${item.remoteIp || 'local'} 👤 ${item.role || 'operator'}
ID: ${item.deviceId || 'n/a'}
${item.scopes ? `
${ item.scopes.map( s => `
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
server.py:126
Finding

Known Default Credentials and API Password Exposed in Frontend Source

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
templates/device_pairings.html:507
Finding

Gateway Authentication Token Is Embedded Unsafely in Page JavaScript

Content
View full analysis
{ btn.textContent = '✓ Copied!'; btn.style.borderColor = '#2ecc71'; btn.style.color = '#2ecc71'; }); } ``` ### Technical Analysis The complete gateway authentication token is read from `openclaw.json` and placed into the generated HTML response as a JavaScript string. The token is therefore present in page source even if the user never clicks the copy button. The value is not serialized with a JavaScript-safe encoder such as Jinja's `tojson`. A token containing quotes, line terminators, or script-closing content could break out of the intended string context. More importantly, the existing stored-XSS vulnerabilities can read this variable or inspect the page source and steal the credential. Providing the full gateway token is not necessary for ordinary device or channel approval operations and therefore exceeds minimum privilege for the core approval workflow. ### Attack Path 1. An authenticated operator opens `/device-pairings`. 2. The serv ...[truncated 618 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
templates/terminal.html:7
Finding

Privileged Pages Load Unpinned Third-Party Dependencies Without Integrity Verification

Content
View full analysis
``` ### Technical Analysis The Python installation instructions do not pin package versions or hashes. This makes installations non-reproducible and may introduce future vulnerable or malicious releases. Privileged dashboard pages execute JavaScript directly from public CDNs without Subresource Integrity attributes. The terminal page gives those scripts access to terminal input and output, while other pages process pairing data and gateway credentials. A compromised CDN response, package release, or dependency resolution path could therefore execute code in a highly privileged browser origin. No malicious dependency was confirmed during this audit; the issue is the unsafe trust and update model. ### Attack Path 1. A user installs unpinned Python packages or opens a dashboard page that requests CDN assets. 2. A dependency source, package release, CDN account, or delivery path is compromised. 3. Modified code is installed or executed by the browser. 4. The malicious code gains access to the dashboard origin, terminal event channel, pairing records, or gateway-token page. 5. It performs unauthorized actions or transmits sensitive data. ### Impact Assessment A compromised Python dependency executes with the server account's operating-system privileges ...[truncated 178 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (22)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill includes a fully interactive shell capability that is unrelated to the observable pairing-management purpose. That mismatch is a strong indicator of hidden remote administration/backdoor functionality, and exploitation would provide arbitrary code execution on the host.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Connected clients can obtain an interactive shell without any explicit disclosure that the application enables arbitrary command execution on the server. In context, this is far beyond pairing management and effectively acts as a concealed remote administration channel.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · server.py (reported line 618)May include surrounding context.

python
master_fd, slave_fd = pty.openpty()
        
        # Use subprocess instead of fork to avoid "multi-threaded fork" warnings
        env = os.environ.copy()
        env['TERM'] = 'xterm-256color'
        env['COLORTERM'] = 'truecolor'

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The client-side approval action embeds a hard-coded password in JavaScript and sends it with every POST to /approve, which exposes the secret to any user who can load the page, inspect source, or intercept browser traffic. The same function performs a sensitive state-changing action immediately on button click without an explicit confirmation step, increasing the risk of accidental or unauthorized approvals if the page is accessed by the wrong user or abused via surrounding application weaknesses.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The client-side code embeds a hardcoded approval password and uses it to perform a privileged pairing approval action from the browser. Any user who can load or inspect this page can recover the credential and invoke the same approval flow directly, defeating access control for a sensitive operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

A sensitive approval credential is sent from browser code in every approval request, making the secret fully exposed to end users, browser tooling, source viewers, and potentially logs or intermediaries. In the context of a pairing dashboard, this directly enables unauthorized approval of device/account pairings and undermines trust in the approval workflow.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
93% confidence
Finding

Allowing Socket.IO connections from any origin weakens browser-based trust boundaries and can enable cross-origin interaction with authenticated users' sessions, especially when paired with powerful socket actions like terminal access. In this application, broad CORS materially increases the blast radius of the shell and approval features.

Content

Scanner excerpt · server.py (reported line 32)May include surrounding context.

python
# Force polling transport only — Werkzeug's dev server doesn't support WebSocket
# with threading async_mode, and the failed upgrade spams ugly 500 errors in the console.
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode, transports=['polling'])

# In-memory storage for pairings (for simplicity)
# In a real app, use a database or more persistent storage.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code defines one authentication mechanism via AUTH_PASSWORD but the login flow actually uses different hardcoded credentials, creating inconsistent and misleading security boundaries. This confusion weakens operator assumptions and leaves sensitive routes protected by guessable embedded credentials rather than a unified secure auth system.

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 · server.py (reported line 304)May include surrounding context.

python
cmd.append('--notify')
        
        print(f"Running command: {' '.join(cmd)}")
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The gateway token is read from local state and injected into a rendered page, exposing a sensitive credential to the browser. Any XSS, browser compromise, malicious extension, or unintended client-side script access could leak that token and allow unauthorized gateway actions.

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 · server.py (reported line 422)May include surrounding context.

python
cmd.append(request_id)

        print(f"Running device approve command: {' '.join(cmd)}")
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

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 · server.py (reported line 475)May include surrounding context.

python
cmd.append(request_id)

        print(f"Running device approve command: {' '.join(cmd)}")
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

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 · server.py (reported line 514)May include surrounding context.

python
def approve_latest_device_pairing():
    """Quick endpoint to approve the most recent pending device pairing."""
    try:
        result = subprocess.run(
            ['openclaw', 'devices', 'approve', '--latest', '--json'],
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The SSH helper introduces remote terminal access with hardcoded connection parameters despite being unjustified by the stated purpose of managing pairings. Hidden remote-access code in an unrelated skill is suspicious and could be used to pivot into another machine or maintain covert access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The SSH helper contains hardcoded remote credentials and uses AutoAddPolicy, combining credential exposure with disabled host authenticity checks. If used, this enables credential theft from source, unsafe connections to untrusted hosts, and unauthorized remote access.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

This code spawns an interactive local shell for a connected client, effectively granting remote command execution on the host through the web interface. In this skill's pairing-management context, an embedded terminal is unrelated and dramatically increases risk because any compromise of the web session becomes full host compromise.

Content

Scanner excerpt · server.py (reported line 622)May include surrounding context.

python
env['TERM'] = 'xterm-256color'
        env['COLORTERM'] = 'truecolor'
        
        process = subprocess.Popen(
            [shell],
            stdin=slave_fd,
            stdout=slave_fd,

Tainted flow: 'shell' from os.environ.get (line 595, credential/environment) → subprocess.Popen (code execution)

Medium
Category
Data Flow
Confidence
77% confidence
Finding

The shell executable is selected from the SHELL environment variable and then executed, so process behavior depends on ambient environment state instead of a fixed trusted path. While this is usually less exploitable than direct user input, it still creates an avoidable execution sink whose impact is amplified because the spawned process is a remote interactive shell.

Content

Scanner excerpt · server.py (reported line 622)May include surrounding context.

python
env['TERM'] = 'xterm-256color'
        env['COLORTERM'] = 'truecolor'
        
        process = subprocess.Popen(
            [shell],
            stdin=slave_fd,
            stdout=slave_fd,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The approve action sends a POST request that authorizes a device pairing, which is a security-relevant operation affecting access control. Unlike rejection, which uses a confirmation dialog, approval proceeds immediately with only a transient status message after initiation and no prior warning or confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This action approves the most recent pending request via a POST call without confirming which device is being approved or warning that access will be granted. Because the operation changes authorization state and may be triggered quickly from the UI, the absence of disclosure increases the risk of unintended approval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code handles a sensitive credential by reading the gateway token into client-side JavaScript and copying it to the user's clipboard, but it provides no warning, confirmation, or explanatory text about the sensitivity of that token. Clipboard placement of credentials can increase accidental disclosure risk because other applications or users may access pasted contents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This HTML/JavaScript file implements an interactive terminal and emits every terminal input event to the server via socket.emit('terminal_input', { data: data }). There is no visible warning in the UI, confirmation step, or explanatory text telling users that their keystrokes will be transmitted to a backend shell session, which is a safety-relevant behavior affecting privacy and system interaction.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The inline comment states 'Remove the pairing from the list', but the implementation only disables the button, marks the item approved, and removes it two seconds later. This is a direct mismatch between the comment and actual behavior, even though the divergence is minor.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.