Back to skill

Security audit

Windows Execution Interface for OpenClaw

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Windows remote-control skill, but it needs review because its powerful commands can use unsafe transport and the advertised filesystem sandbox is not enforced by the client.

Install only if you intentionally need full remote control of a Windows host and trust the Clawdos server. Use HTTPS for any non-local connection, keep the API key narrowly scoped, confirm shell and delete operations before running them, and ensure the server binds credentials to the intended filesystem root rather than relying on this client.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/clawdos.py:19
Finding

Authenticated API traffic can be transmitted over plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/clawdos.py, lines 19-38
Vulnerability Type: Insecure transport of authentication credentials and privileged commands
Risk Level: High

Technical Analysis

The client defaults to an unencrypted HTTP endpoint and does not require HTTPS when a non-loopback or remote address is configured. The API key is included in the X-Api-Key header on authenticated requests.

python
BASE_URL = os.getenv("CLAWDOS_BASE_URL", "http://127.0.0.1:17171")
API_KEY = os.getenv("CLAWDOS_API_KEY", "")
TIMEOUT = int(os.getenv("CLAWDOS_TIMEOUT", "30"))
FS_ROOT_ID = int(os.getenv("CLAWDOS_FS_ROOT_ID", "0"))

def get_headers(auth=True):
    if auth:
        if not API_KEY:
            print(json.dumps({"error": "CLAWDOS_API_KEY environment variable is not set. Please configure the skill in OpenClaw."}), file=sys.stderr)
            sys.exit(1)
        return {"X-Api-Key": API_KEY}
    return {}

def api_get(path, params=None, auth=True):
    url = f"{BASE_URL}{path}"
    resp = requests.get(url, params=params, headers=get_headers(auth), timeout=TIMEOUT)
    resp.raise_for_status()
    return resp

def api_post(path, payload):
    url = f"{BASE_URL}{path}"
    resp = requests.post(url, json=payload, headers=get_headers(True), timeout=TIMEOUT)
    resp.raise_for_status()
    return resp.json()

While plaintext HTTP over loopback may be acceptable under a narrow local-only deployment model, the Skill explicitly supports controlling a Windows host remotely. A user can configure CLAWDOS_BASE_URL with a remote http:// address without any warning or refusal.

In that configuration, a network-positioned attacker can observe the API key, command arguments, typed text, filesystem content, screenshots, and API responses. Base64 encoding used by the file-transfer functions is only a transport representation and provides no confidentiality.

The client also does not ...[truncated 1569 chars]

Remediation
View remediation

Remediation Suggestions

  • Require https:// for every non-loopback CLAWDOS_BASE_URL.
  • Permit plaintext HTTP only through an explicit local-development option and only when the parsed hostname is a verified loopback address.
  • Parse and validate the URL with urllib.parse; reject embedded credentials, unexpected schemes, fragments, and malformed hostnames.
  • Emit a clear error rather than silently sending the API key over an insecure connection.
  • Configure the server with a certificate issued by a trusted private or public CA. For high-value deployments, consider certificate or public-key pinning.
  • Use short-lived, narrowly scoped credentials instead of a static bearer-equivalent API key where the service supports them.
  • Separate capabilities into scoped credentials, particularly shell execution, screen capture, input control, and filesystem access.
  • Add automated tests proving that remote HTTP URLs are rejected and that HTTPS certificate verification remains enabled.
  • Document that Base64 is not encryption and must not be relied on to protect screenshots or file contents.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/clawdos.py:96
Finding

Caller-controlled rootId can override the configured filesystem sandbox root

Content
View full analysis

Vulnerability Details

File Location: scripts/clawdos.py, lines 96-140
Vulnerability Type: Client-side sandbox-root override and excessive authorization scope
Risk Level: High

Technical Analysis

The Skill documentation states that all filesystem operations are restricted to the sandbox root configured through CLAWDOS_FS_ROOT_ID. The implementation, however, only inserts that configured root when the caller has not supplied a rootId.

python
elif action == "fs_list":
    if "rootId" not in kwargs: kwargs["rootId"] = FS_ROOT_ID
    res = api_get("/v1/fs/list", params=kwargs).json()
elif action == "fs_read":
    if "rootId" not in kwargs: kwargs["rootId"] = FS_ROOT_ID
    raw = api_get("/v1/fs/read", params=kwargs).json()
    b_data = base64.b64decode(raw["data"])
    if args.out:
        with open(args.out, "wb") as f:
            f.write(b_data)
        res = {"success": True, "saved_to": args.out}
    else:
        try:
            res = b_data.decode("utf-8")
            print(res)
            return
        except UnicodeDecodeError:
            print(json.dumps({"error": "File is binary, use --out to save it"}), file=sys.stderr)
            sys.exit(1)
elif action == "fs_write":
    if "rootId" not in kwargs: kwargs["rootId"] = FS_ROOT_ID
    if args.file:
        with open(args.file, "rb") as f:
            b_data = f.read()
        kwargs["data"] = base64.b64encode(b_data).decode("ascii")
        kwargs["encoding"] = "base64"
    elif "content" in kwargs:
        content = kwargs.pop("content")
        kwargs["data"] = base64.b64encode(content.encode("utf-8")).decode("ascii")
        kwargs["encoding"] = "base64"
    res = api_post("/v1/fs/write", kwargs)
elif action == "fs_mkdir":
    if "rootId" not in kwargs: kwargs["rootId"] = FS_ROOT_ID
    res = api_post("/v1/fs/mkdir", kwargs)
elif action == "fs_delete":
    if "rootId" not in kwargs: kwar
...[truncated 3177 chars]
Remediation
View remediation

Remediation Suggestions

  • Never accept rootId from user-controlled --args for sandboxed filesystem actions.

  • Unconditionally assign the configured value before every filesystem request:

    python
    kwargs["rootId"] = FS_ROOT_ID
    
  • Prefer removing any supplied value and rejecting the request with an explicit error so attempts are visible:

    python
    if "rootId" in kwargs:
        raise ValueError("rootId is managed by configuration and cannot be overridden")
    kwargs["rootId"] = FS_ROOT_ID
    
  • Validate CLAWDOS_FS_ROOT_ID at startup and fail closed when it is absent or uses a sentinel such as 0, unless that value is explicitly known to represent a safe root.

  • Bind each API key to exactly one server-side root and derive the root from authenticated server state rather than request parameters.

  • On the server, reject any rootId not assigned to the authenticated principal, even if the identifier references an otherwise valid root.

  • Use separate credentials for filesystem operations and shell execution. Do not allow a filesystem-scoped credential to invoke arbitrary shell commands.

  • Add tests covering explicit rootId values for every filesystem action and verify that no request can escape the configured root.

  • Update documentation to accurately distinguish client-side controls from server-enforced authorization guarantees.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (8)

Tainted flow: 'url' from os.getenv (line 41, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/clawdos.py (reported line 36)May include surrounding context.

python
def api_get(path, params=None, auth=True):
    url = f"{BASE_URL}{path}"
    resp = requests.get(url, params=params, headers=get_headers(auth), timeout=TIMEOUT)
    resp.raise_for_status()
    return resp

Tainted flow: 'url' from os.getenv (line 41, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/clawdos.py (reported line 42)May include surrounding context.

python
def api_post(path, payload):
    url = f"{BASE_URL}{path}"
    resp = requests.post(url, json=payload, headers=get_headers(True), timeout=TIMEOUT)
    resp.raise_for_status()
    return resp.json()

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares powerful capabilities through environment variables and network access but does not define an explicit tool scope such as permissions or allowed-tools. In a skill that enables remote Windows automation and shell command execution, missing scope boundaries increases the chance that the agent can invoke this skill or supporting tools more broadly than intended, weakening least-privilege controls and reviewability.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/clawdos.py (reported line 42)May include surrounding context.

python
def api_post(path, payload):
    url = f"{BASE_URL}{path}"
    resp = requests.post(url, json=payload, headers=get_headers(True), timeout=TIMEOUT)
    resp.raise_for_status()
    return resp.json()

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/clawdos.py (reported line 64)May include surrounding context.

python
try:
        if action == "health":
            res = api_get("/v1/health", auth=False).json()
        elif action == "get_env":
            res = api_get("/v1/env").json()
        elif action == "window_list":

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill supports environment retrieval and screen capture, both of which can expose highly sensitive information such as secrets, tokens, user data, or visible session contents, yet the CLI provides no disclosure or friction. Because this skill is specifically for remote host inspection/control, the surrounding context makes silent collection of this data more dangerous, not less.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill permits delete and move operations against the remote filesystem without user-facing warning, confirmation, or path safety checks. In this skill context, that can lead to accidental or unauthorized destruction or tampering of files on the controlled Windows host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI exposes shell command execution on the target host with no confirmation, guardrails, or restriction. In the context of a remote Windows automation skill, this materially increases the chance of arbitrary command execution, destructive actions, persistence, or data exfiltration if the tool is invoked unsafely or by a compromised agent.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.