Back to skill

Security audit

OpenClaw Agent Mesh

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate peer-messaging purpose, but its network-facing inbox handling has serious validation gaps that could let reachable peers write JSON files outside the intended state directory.

Review before installing or running as a server. Use it only on a trusted network, bind to 127.0.0.1 unless remote peers are required, keep the state directory under a low-privilege account, and fix identifier validation/path containment before accepting network traffic.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mesh.py:149
Finding

Network-Controlled Path Traversal Allows Arbitrary JSON File Writes

Content
View full analysis
pathlib.Path: return PEERS_DIR / f"{agent_id}.json" ``` ```python def cmd_receive_contact(args): payload = load_json(pathlib.Path(args.file)) unsigned = {k: v for k, v in payload.items() if k != "signature"} sender = payload.get("from", {}) ok = verify_signature(unsigned, payload.get("signature", ""), sender.get("public_key", "")) result = {"verified": ok, "request_id": payload.get("request_id")} if ok: path = REQ_IN_DIR / f"{payload['request_id']}.json" save_json(path, payload) result["saved"] = str(path) print(json.dumps(result, indent=2)) ``` ```python def cmd_approve_request(args): p = REQ_IN_DIR / f"{args.request_id}.json" if not p.exists(): raise SystemExit("Request not found") payload = load_json(p) sender = payload["from"] peer = { "agent_id": sender["agent_id"], "display_name": sender.get("display_name"), "endpoint": sender.get("endpoint"), "public_key": sender["public_key"], "fingerprint": sender["fingerprint"], "trusted_at": now_iso(), "source_request_id": payload["request_id"], } save_json(peer_path(sender["agent_id"]), peer) ``` ```python def cmd_receive_message(args): payload = load_json(pathlib.Path(args.file)) sender_id = payload.get("from") peer = load_peer(sender_id) unsigned = {k: v for k, v in payload.items() if k != "signature"} ok = verify_signature(unsigned, payload.get("signature", ""), peer["public_key"]) result = {"verified": ok, "message_id": payload.get("message_id")} if ok: path = MSG_IN_DIR / f"{payload['message_id']}.json" save_json(path, payload) result["saved"] = str(path) ``` # ...[truncated 2161 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mesh.py:163
Finding

Missing Envelope Freshness, Recipient, Schema, and Replay Validation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/server.py:36
Finding

Unbounded HTTP Request Bodies Permit Denial of Service

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/mesh.py:27
Finding

Mesh Messages and State Files May Have Excessively Permissive Local Permissions

Content
View full analysis
None: for p in [STATE_DIR, PEERS_DIR, REQ_IN_DIR, REQ_OUT_DIR, MSG_IN_DIR, MSG_OUT_DIR]: p.mkdir(parents=True, exist_ok=True) ``` ```python def save_json(path: pathlib.Path, obj: Any) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(obj, indent=2, ensure_ascii=False) + "\n") ``` ```python PRIVATE_KEY_PATH.write_bytes(private_pem) PUBLIC_KEY_PATH.write_bytes(public_pem) os.chmod(PRIVATE_KEY_PATH, 0o600) save_json(IDENTITY_PATH, identity) ``` ### Technical Analysis The private key is explicitly restricted to mode `0600`, but the state directories and JSON files rely on the process umask. Under common umask settings, directories may be created as `0755` and files as `0644`. These files contain plaintext direct messages, contact-request purposes, endpoint information, public identity metadata, and trust relationships. On a multi-user system, relying on ambient umask configuration may allow other local users to traverse the state directory and read this information. ### Attack Path 1. A user initializes and runs the Skill under a default or permissive umask. 2. Mesh directories and JSON records are created with group- or world-readable permissions. 3. Another local account enumerates `~/.openclaw/agent-mesh`. 4. That account reads stored incoming and outgoing messages, requests, or peer metadata without authorization. ### Impact Assessment Other local users may obtain plaintext communications and mesh relationship metadata. The private signing key is explicitly protected after initialization and is not directly exposed by this finding. Scope is limited to local accounts that can traverse the relevant parent directories. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

Most of the declared workflow is broadly represented: identity init, discovery response generation, contact request creation/receipt, approval/rejection, trust storage, and direct message send/receive with signatures. However, key parts of the description overstate the implemented behavior. The code is purely a CLI utility and local file store; it does not start or run any HTTP server despite the description explicitly claiming lightweight HTTP server support for discovery and inbox handling. Its 'scan' command is not LAN scanning or nearby-node discovery in the usual sense—it only fetches /agent-mesh/discovery from URLs explicitly passed as arguments. Also, while approval/rejection exists locally, there is no code to transmit approvals or rejections back to requesting peers. These are material behavior gaps relative to the declared description, so this should be flagged as a mismatch.

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

python
def run_mesh(args, state_dir: str):
    env = os.environ.copy()
    env['OPENCLAW_AGENT_MESH_DIR'] = state_dir
    res = subprocess.run([sys.executable, str(MESH)] + args, env=env, capture_output=True, text=True)
    return res.returncode, res.stdout, res.stderr

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill describes capabilities that require filesystem access, shell execution, networking, and likely environment access, but it does not declare any explicit tool scope or permission boundaries. In an agent framework, missing scope declarations can cause over-broad execution privileges, making it easier for the skill to read/write unintended files, invoke arbitrary commands, or perform network actions without clear user consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation instructs users to run a server bound to 0.0.0.0, which exposes it on all network interfaces, but it does not warn about the security implications. In the context of a peer-messaging service that accepts discovery, contact requests, and messages, this can unintentionally expose an inbox endpoint to untrusted local networks or broader networks if the host is misconfigured.

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 · scripts/mesh.py (reported line 61)May include surrounding context.

python
def run(cmd: List[str], input_bytes: bytes | None = None) -> subprocess.CompletedProcess:
    return subprocess.run(cmd, input=input_bytes, capture_output=True, check=True)


def generate_keypair() -> tuple[bytes, bytes]:

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

python
def run_mesh(args, state_dir: str):
    env = os.environ.copy()
    env['OPENCLAW_AGENT_MESH_DIR'] = state_dir
    res = subprocess.run([sys.executable, str(MESH)] + args, env=env, capture_output=True, text=True)
    return res.returncode, res.stdout, res.stderr