Back to skill

Security audit

RealWorldClaw

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it controls real hardware and handles credentials with weak safety and security guardrails.

Install only if you are comfortable letting an agent send commands to real ESP32-connected hardware. Use it on trusted networks, avoid entering real passwords on the command line, verify `config.json` before login or registration, and treat automation rules as live hardware controls that may repeat until stopped.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/rwc.py:75
Finding
MQTT TLS Certificate Verification Is Explicitly Disabled<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rwc.py:75-78` **Vulnerability Type**: Improper TLS certificate validation **Risk Level**: High ### Vulnerable Code ```python client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) if self.code: client.username_pw_set("bblp", self.code) client.tls_set(cert_reqs=ssl.CERT_NONE) client.tls_insecure_set(True) return client ``` ### Technical Analysis The MQTT client enables TLS but explicitly disables certificate validation through both `cert_reqs=ssl.CERT_NONE` and `tls_insecure_set(True)`. Consequently, the client cannot authenticate that it is communicating with the intended ESP32 or MQTT broker. This defeats the identity-verification property of TLS. An attacker capable of intercepting local network traffic can present an arbitrary certificate, impersonate the broker, and observe or modify MQTT communications. The device access code is configured as the MQTT password and may be exposed during such an interception. Because this client sends physical actuator commands, successful interception can have effects beyond confidentiality loss. ### Attack Path 1. An attacker obtains a position on the same local network or otherwise gains the ability to redirect MQTT traffic. 2. The attacker redirects traffic intended for the configured device IP to a malicious MQTT broker. 3. The malicious broker presents an untrusted or self-signed certificate. 4. The client accepts the certificate because verification is disabled. 5. The client authenticates using the configured access code. 6. The attacker captures credentials, supplies forged telemetry, or receives and manipulates actuator commands. 7. The attacker can subsequently impersonate the broker or use recovered credentials to attempt unauthorized device control. ### Impact Assessment A successful attacker may obtain the MQTT device access code, compromise telemetry integrity, monitor device activity, and interfere with relay, servo, LED, bu ...[truncated 139 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `tls_insecure_set(True)`. - Replace `ssl.CERT_NONE` with `ssl.CERT_REQUIRED`. - Configure a trusted CA certificate using `tls_set(ca_certs=...)` or a properly maintained system trust store. - Validate the expected broker hostname or device identity. - Use a private CA or certificate pinning where devices use locally issued certificates. - Fail closed when certificate verification cannot be completed. - Rotate existing device access codes if the client has operated on an untrusted network. - Consider mutual TLS so that both the device and client authenticate each other. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/rwc.py:216
Finding
Arbitrary JSON Fields Can Override Allowlisted Physical Device Commands<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rwc.py:216-223` **Vulnerability Type**: Insufficient authorization and command-parameter validation **Risk Level**: High ### Vulnerable Code ```python action_name = args.action if action_name not in ACTIONS: print(f"❌ Unknown action '{action_name}'. Available: {list(ACTIONS.keys())}") sys.exit(1) cmd = dict(ACTIONS[action_name]) if args.value: cmd.update(json.loads(args.value)) client = DeviceClient(dev) ``` ### Technical Analysis The action name is checked against the `ACTIONS` allowlist, but the resulting command dictionary is subsequently updated with unrestricted caller-supplied JSON. Python's `dict.update()` replaces existing values, so a caller can overwrite security-sensitive fields such as `command`, `pin`, and `value`. The action allowlist therefore does not form an effective authorization boundary. A caller can select any accepted action name and then transform its low-level device command into another command not represented by that action. No per-action schema, allowed-key validation, value-range validation, or protection for immutable command fields is implemented. ### Attack Path 1. A caller chooses an allowlisted action such as `led`. 2. The caller supplies a crafted value, for example: ```bash python3 scripts/rwc.py act \ --device my-esp32 \ --action led \ --value '{"command":"gpio","pin":12,"value":1}' ``` 3. The script copies the allowlisted `led` command. 4. `cmd.update(...)` overwrites or adds the attacker-controlled command fields. 5. The modified command is serialized and published to the device request topic. 6. If the firmware accepts the fields, the unintended GPIO or capability is activated. ### Impact Assessment A user or agent that is expected to invoke only predefined actions may bypass those restrictions and issue unintended low-level commands. Depending on the connected hardware and firmware validation, this could activa ...[truncated 267 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Define a strict input schema for each supported action. - Maintain immutable fields such as `command` and fixed GPIO assignments separately from caller-controlled values. - Permit only explicitly approved keys for each action. For example, an LED action should accept only validated color channels. - Reject unknown fields instead of merging them into the command. - Validate all values by type and range, such as RGB values from 0 through 255 and servo positions within safe limits. - Do not expose raw GPIO selection unless it is an explicitly authorized administrative feature. - Add corresponding validation in device firmware because client-side validation alone is not a complete security boundary. - Add tests proving that `--value` cannot replace `command`, `pin`, or other protected fields. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/rwc.py:123
Finding
Login and Registration Credentials Can Be Sent to an Arbitrary Configured API Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rwc.py:123-143` and `scripts/rwc.py:285` **Vulnerability Type**: Unvalidated credential destination and possible cleartext credential transmission **Risk Level**: High ### Vulnerable Code ```python class PlatformAPI: """HTTP client for RealWorldClaw cloud platform.""" def __init__(self, base_url: str = DEFAULT_API, token: str = ""): if not HAS_HTTPX: print("❌ httpx not installed. Run: pip install httpx") sys.exit(1) headers = {} if token: headers["Authorization"] = f"Bearer {token}" self.http = httpx.Client(base_url=base_url, headers=headers, timeout=30) def health(self) -> dict: return self.http.get("/health").json() def modules(self) -> dict: return self.http.get("/modules").json() def register(self, username: str, email: str, password: str) -> dict: return self.http.post("/auth/register", json={ "username": username, "email": email, "password": password }).json() def login(self, email: str, password: str) -> dict: return self.http.post("/auth/login", json={ "email": email, "password": password }).json() ``` The configurable URL is used without origin or scheme validation: ```python def cmd_api(args, config): """Platform API commands.""" api = PlatformAPI(config.get("api_url", DEFAULT_API)) ``` ### Technical Analysis The API base URL is loaded from `config.json` and passed directly to `httpx.Client`. The code does not require HTTPS, validate the destination hostname, or restrict credential-bearing requests to an approved API origin. The `register` and `login` methods transmit plaintext password values in request bodies to this configured endpoint. HTTPS protects the default URL, but a modified configuration can select an attacker-controlled HTTPS endpoint or an unencrypted HTTP endpoint. This is especially dangerou ...[truncated 1258 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require the `https` URL scheme for every endpoint receiving credentials. - Enforce an explicit allowlist of trusted API hostnames for normal operation. - If custom servers are required, place that functionality behind an explicit opt-in warning and separate configuration flag. - Reject URLs containing embedded credentials, unexpected ports, fragments, or malformed hostnames. - Ensure redirects cannot forward authorization data or credential-bearing requests to an untrusted origin. - Display the validated destination before credential submission when a non-default endpoint is used. - Consider certificate or public-key pinning for the official API where operationally practical. - Protect `config.json` with restrictive filesystem permissions and document its security sensitivity. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rwc.py:335
Finding
Passwords Are Accepted Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rwc.py:335-341`; documented at `SKILL.md:63` **Vulnerability Type**: Sensitive information exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```python p_reg = p_api_sub.add_parser("register") p_reg.add_argument("--username", required=True) p_reg.add_argument("--email", required=True) p_reg.add_argument("--password", required=True) p_login = p_api_sub.add_parser("login") p_login.add_argument("--email", required=True) p_login.add_argument("--password", required=True) ``` The documented usage encourages this behavior: ```bash python3 scripts/rwc.py api register --username x --email x --password x ``` ### Technical Analysis Secrets supplied as command-line arguments may be visible in shell history, process listings, audit telemetry, terminal recording, job-control metadata, crash reports, or wrapper-script logs. The implementation requires a password argument and the documentation explicitly demonstrates entering it on the command line. Although operating-system restrictions vary, command-line arguments should not be treated as a secure secret-input channel. ### Attack Path 1. A user follows the documented command and enters a real password after `--password`. 2. The shell stores the complete command in its history, or a local process-monitoring facility captures the process arguments. 3. A local user, support tool, log collector, or later compromise obtains access to that record. 4. The plaintext password is recovered. 5. The password is used to access the RealWorldClaw account or another service if the credential was reused. ### Impact Assessment Exposure can lead to compromise of the user's cloud-platform account and any devices or modules authorized through that account. The immediate attack generally requires access to local process information, shell history, or collected logs. Password reuse may increase the scope beyond this project. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Read passwords interactively with `getpass.getpass()` rather than requiring `--password`. - Support protected standard input for non-interactive automation. - Where appropriate, integrate with an operating-system credential store or secret manager. - Remove password-bearing command examples from `SKILL.md`. - If a command-line password option must remain for compatibility, clearly mark it as insecure and make interactive input the default. - Avoid logging parsed arguments or request bodies containing passwords. - Recommend credential rotation if passwords have previously been entered into shared terminals or logged shells. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding
Python Dependencies Are Installed Without Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:14-17` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash pip install httpx paho-mqtt ``` ### Technical Analysis The installation instructions resolve mutable package versions from the user's configured Python package index. No exact versions, lock file, hashes, or index restrictions are supplied. The reviewed package names match the imports in the script, and the audit found no evidence that they are typographical imitations. Nevertheless, unpinned installation is not reproducible and can automatically consume a future compromised, malicious, or incompatible release. Python package installation can execute package build logic, and imported dependencies execute code in the context of the invoking user. ### Attack Path 1. A dependency release or its distribution account is compromised, or the user's package-index configuration resolves an unsafe source. 2. The user follows the documented unpinned installation command. 3. `pip` resolves the affected package version because no reviewed version or hash is required. 4. Malicious installation or imported runtime code executes with the user's privileges. 5. The dependency may access project files, configuration credentials, network resources, and devices available to the process. ### Impact Assessment A compromised dependency could execute arbitrary code with the privileges of the user installing or running the skill. This could expose `config.json`, including device access codes, alter automation rules, interfere with device commands, or compromise other files accessible to the account. The finding represents supply-chain exposure rather than evidence that the currently named packages are malicious. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin every dependency to a reviewed exact version. - Maintain a lock file generated from reviewed requirements. - Use hash verification, such as `pip install --require-hashes`, for reproducible installation. - Configure an approved package index and prevent unintended dependency resolution from untrusted extra indexes. - Regularly scan pinned dependencies for known vulnerabilities. - Test and review upgrades before changing pinned versions. - Prefer binary wheels from trusted sources and avoid unnecessary source builds. - Document the supported Python version and dependency-update process. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Missing User Warnings

High
Confidence
95% confidence
Finding
The act command performs immediate physical-world operations on relays, servos, LEDs, and buzzers without confirmation, authorization checks, or safety interlocks. In a skill explicitly designed to control real hardware, silent actuation materially increases the risk of unsafe motion, power switching, equipment damage, or harm caused by prompt injection or accidental invocation.

Missing User Warnings

High
Confidence
97% confidence
Finding
The monitor loop automatically converts sensor input into real-world actions based on persisted rules, with no approval step, validation of rule safety, or fail-safe constraints. Because this skill's core context is physical device control, autonomous triggering is especially dangerous: malformed sensor data, spoofed MQTT messages, or unsafe rules can repeatedly actuate hardware without human oversight.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill exposes capabilities that imply file access and network communication but does not declare any explicit tool scope or permission boundaries. In an agent environment, this can lead to overbroad tool use, making it harder to enforce least privilege and increasing the chance that the skill can read local configuration/secrets or send device commands without clear policy controls.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This skill enables physical-world actions such as relay, servo, LED, buzzer, and automation control, but it does not prominently warn that executing these commands can cause real-world effects or require user confirmation and safety checks. In the context of IoT and actuator control, an agent could trigger unsafe or unintended actions that affect equipment, environments, or people.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The code writes rule data to disk via RULES_PATH.write_text(), creating persistent changes to the local filesystem. Although the surrounding function manages rules, there is no explicit warning in the save path itself or adjacent comments/docstrings disclosing that user actions will modify a local file.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The manifest frames this skill around controlling ESP32/IoT devices, reading sensors, actuating hardware, and creating automation rules. Implementing user account registration and login against a cloud platform adds identity-management capability that is not clearly justified by the stated physical-device control purpose.

Static analysis

No suspicious patterns detected.