Back to skill

Security audit

AgentsMakingFriends

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real A2A bridge, but its server can expose the local main OpenClaw agent over the network with unsafe defaults and weak secret handling.

Review carefully before installing. Do not run the server as documented on a public or shared network; use localhost or a protected network, require authentication and TLS, avoid storing tokens in workspace docs, prevent token logging, and route remote requests to a constrained low-privilege agent rather than the main agent.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/a2a_server.py:37
Finding
Unauthenticated Network Exposure of the Privileged Main Agent## Vulnerability Details **File Location**: `scripts/a2a_server.py:37-43`, `scripts/a2a_server.py:111-174`, `scripts/a2a_server.py:207` **Vulnerability Type**: Missing authentication and violation of least privilege **Risk Level**: Critical ### Vulnerable Code ```python def check_auth(self) -> bool: if not self.required_token: return True auth_header = self.headers.get('Authorization', '') if auth_header.startswith('Bearer '): return auth_header[7:] == self.required_token return False ``` ```python def handle_message_send(self, params: Dict[str, Any], request_id: str) -> Dict[str, Any]: message = params.get('message', {}) parts = message.get('parts', []) # Extract text text = "" for part in parts: if part.get('type') == 'text': text = part.get('text', '') break if not text: return { "jsonrpc": "2.0", "error": {"code": -32602, "message": "No text in message"}, "id": request_id } # Call OpenClaw agent print(f"[A2A] Received: {text}") try: result = subprocess.run( ['openclaw', 'agent', '--agent', 'main', '--message', text, '--json'], capture_output=True, text=True, timeout=120 ) if result.returncode == 0: try: agent_response = json.loads(result.stdout) response_text = agent_response.get('content', result.stdout) except json.JSONDecodeError: response_text = result.stdout else: response_text = f"Error: {result.stderr}" print(f"[A2A] Response: {response_text[:100]}...") except subprocess.TimeoutExpired: response_text = "Error: Agent timeout" except Exception as e: ...[truncated 2026 chars]
Remediation
## Remediation Suggestions - Require authentication by default and refuse to start without an authentication configuration when binding to a non-loopback address. - Bind to `127.0.0.1` by default; require an explicit secure option to bind to external interfaces. - Route remote requests to a dedicated least-privileged agent rather than `main`. - Disable command execution, unrestricted file access, secret access, and other high-risk tools for the remote-facing agent. - Add an authorization policy that limits callers to explicitly approved capabilities. - Require user approval before performing sensitive operations initiated by remote messages. - Use a constant-time token comparison and support token rotation, expiration, and revocation. - Add request rate limits, audit logging, and network-level access controls. - Change the documented quick start to a secure authenticated configuration.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/a2a_client.py:24
Finding
Bearer Tokens and Agent Messages Can Be Transmitted over Plaintext HTTP## Vulnerability Details **File Location**: `scripts/a2a_client.py:24-27`, `scripts/a2a_client.py:30-42`, `scripts/a2a_client.py:45-68`; insecure HTTP usage is also documented in `SKILL.md:16-19` and `SKILL.md:48-55` **Vulnerability Type**: Plaintext transmission of sensitive information **Risk Level**: High ### Vulnerable Code ```python def __init__(self, agent_url: str, token: Optional[str] = None): self.agent_url = agent_url.rstrip('/') self.headers = {'Content-Type': 'application/json'} if token: self.headers['Authorization'] = f'Bearer {token}' ``` ```python def get_agent_card(self) -> Dict[str, Any]: """Get Agent Card (discover agent capabilities)""" url = f"{self.agent_url}/.well-known/agent.json" req = urllib.request.Request(url, headers=self.headers) try: with urllib.request.urlopen(req, timeout=30) as response: return json.loads(response.read().decode('utf-8')) except urllib.error.HTTPError: # Try alternate path url = f"{self.agent_url}/agent-card" req = urllib.request.Request(url, headers=self.headers) with urllib.request.urlopen(req, timeout=30) as response: return json.loads(response.read().decode('utf-8')) ``` ```python def send_message(self, message: str, context_id: Optional[str] = None) -> Dict[str, Any]: """Send message to remote agent (JSON-RPC 2.0)""" request_body = { "jsonrpc": "2.0", "method": "message/send", "id": "1", "params": { "message": { "role": "user", "parts": [{"type": "text", "text": message}] } } } if context_id: request_body["params"]["contextId"] = context_id req = urllib.request.Request( f"{self.agent_url}/rpc", data=json.dumps(request_body).encode('utf-8'), heade ...[truncated 2056 chars]
Remediation
## Remediation Suggestions - Require `https://` for all non-loopback destinations. - Reject plaintext URLs before constructing or sending a request. - Permit HTTP only through an explicit development-only override restricted to loopback addresses. - Retain normal certificate and hostname verification; do not add insecure TLS-bypass options. - Update `SKILL.md`, `agent_card.json`, usage strings, and API examples to use HTTPS exclusively. - Avoid sending authorization credentials during unauthenticated capability discovery unless the endpoint explicitly requires them. - Apply strict redirect policies so credentials cannot be forwarded to an unintended destination. - Use short-lived, narrowly scoped credentials and rotate any token that may have crossed plaintext HTTP.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/a2a_server.py:209
Finding
Bearer Tokens Are Exposed through Command-Line Arguments, Plaintext Configuration, and Server Logs## Vulnerability Details **File Location**: `scripts/a2a_client.py:102-106`, `scripts/a2a_server.py:195-199`, `scripts/a2a_server.py:209-212`, and `SKILL.md:48-55` **Vulnerability Type**: Insecure secret handling **Risk Level**: High ### Vulnerable Code ```python agent_url = sys.argv[1] message = sys.argv[2] token = sys.argv[3] if len(sys.argv) > 3 else None client = A2AClient(agent_url, token) ``` ```python parser = argparse.ArgumentParser(description='A2A Server for OpenClaw Agent') parser.add_argument('--port', type=int, default=8080, help='Server port (default: 8080)') parser.add_argument('--token', type=str, help='Bearer Token (optional)') parser.add_argument('--name', type=str, default='OpenClaw Agent', help='Agent name') parser.add_argument('--description', type=str, default='OpenClaw Personal AI Assistant', help='Agent description') args = parser.parse_args() ``` ```python print(f"🦞 A2A Server started!") print(f"📍 URL: http://0.0.0.0:{args.port}") print(f"📋 Agent Card: http://0.0.0.0:{args.port}/.well-known/agent.json") print(f"🔐 Auth: {'Bearer Token: ' + args.token if args.token else 'No auth'}") ``` The documentation also recommends plaintext token storage: ```markdown ### A2A Agents - Remote Agent Name: URL: http://1.2.3.4:8080/a2a Token: your-bearer-token ``` ### Technical Analysis Both client and server accept bearer tokens as process arguments. Process command lines may be visible in process listings, monitoring systems, shell history, diagnostics, or job-runner metadata. The server additionally prints the complete token to standard output, which can be captured by terminals, service managers, centralized logging systems, or CI logs. The configuration example recommends placing the token directly in `TOOLS.md`, where it may be accessible to workspace readers or accidentally committed, synchronized, backed up, or included in diagnostic bundles. ### Attack P ...[truncated 876 chars]
Remediation
## Remediation Suggestions - Remove positional and `--token` command-line secret arguments. - Read tokens from a secret manager, an interactive hidden prompt, or a permission-restricted file descriptor. - If environment variables are supported, document their exposure limitations and prefer a dedicated secret manager for production. - Never print a token or any reversible portion of it; log only whether authentication is enabled. - Redact authorization headers and tokens from diagnostics and exception output. - Do not store credentials in `TOOLS.md` or other general workspace documentation. - Store secret files outside the repository with owner-only permissions. - Use scoped, short-lived tokens with rotation and revocation support. - Rotate any credentials previously passed through process arguments or emitted to logs.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/a2a_server.py:66
Finding
Unbounded Request Body Read Allows Remote Denial of Service## Vulnerability Details **File Location**: `scripts/a2a_server.py:66-80` **Vulnerability Type**: Missing request-size validation and resource exhaustion **Risk Level**: High ### Vulnerable Code ```python def do_POST(self): if not self.check_auth(): self.send_json_response({"error": "Unauthorized"}, 401) return content_length = int(self.headers.get('Content-Length', 0)) body = self.rfile.read(content_length).decode('utf-8') try: request = json.loads(body) except json.JSONDecodeError: self.send_json_response({ "jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": None }) return ``` The server is instantiated with the single-threaded implementation: ```python server = HTTPServer(('0.0.0.0', args.port), OpenClawA2AHandler) ``` ### Technical Analysis The server converts the attacker-controlled `Content-Length` header to an integer and passes it directly to `read()` without imposing a maximum request size. A client can request an extremely large allocation or slowly transmit a declared body while the server waits for completion. This behavior is amplified by the use of Python's single-threaded `HTTPServer`: one slow or oversized request can prevent the server from processing other clients. Invalid nonnumeric `Content-Length` values may also raise an uncaught `ValueError`, terminating the individual request unexpectedly. ### Attack Path 1. An attacker connects to the externally bound HTTP service. 2. If authentication is disabled, no credentials are needed; if enabled, any authorized or compromised caller can perform the same attack. 3. The attacker submits a POST request with an extremely large `Content-Length`, or sends the body very slowly. 4. The handler blocks while reading the declared number of bytes or consumes excessive memory while storing the bo ...[truncated 615 chars]
Remediation
## Remediation Suggestions - Define a strict maximum request-body size appropriate for text A2A messages. - Validate that `Content-Length` is present, numeric, nonnegative, and below the configured limit. - Return HTTP 411 for missing required lengths, HTTP 400 for malformed lengths, and HTTP 413 for oversized requests. - Apply socket and request-read timeouts to mitigate slow-request attacks. - Avoid reading the entire body before validation where streaming or bounded reads are possible. - Use a production-grade HTTP server or reverse proxy with body-size limits, connection limits, concurrency controls, and timeouts. - Add per-client rate limiting and total request quotas. - Keep authentication mandatory, while recognizing that authentication alone does not replace resource limits.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (10)

Exfiltration Commands

High
Category
Prompt Injection
Content
return json.loads(response.read().decode('utf-8'))
    
    def send_message(self, message: str, context_id: Optional[str] = None) -> Dict[str, Any]:
        """Send message to remote agent (JSON-RPC 2.0)"""
        request_body = {
            "jsonrpc": "2.0",
            "method": "message/send",
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises and instructs use of network and shell-capable scripts but does not declare any tool scope or permission boundaries. In an agent environment, this increases the chance that the skill is invoked with broader-than-expected capabilities, making misuse, unintended outbound connections, or unsafe command execution harder to govern.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill recommends exposing OpenClaw as a network-accessible A2A service without any warning about authentication, authorization, network trust boundaries, or attack surface. Because this service is specifically designed for inter-agent task execution, exposing it insecurely could permit unauthorized requests, prompt injection relay, abuse of connected tools, or broader compromise of the host agent environment.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The documentation tells users to place a bearer token directly in TOOLS.md, which encourages storing secrets in a likely plaintext, shareable, and version-controllable file. That raises the risk of credential leakage through logs, screenshots, backups, repository commits, or downstream agent/tool exposure, enabling unauthorized access to remote agents.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The agent card advertises an 'execute' capability even though this service is presented as an A2A communication bridge. Advertising generic execution broadens perceived authority and may cause remote agents or orchestrators to invoke the service for command-like actions, increasing the chance of unsafe use or over-trust.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The server accepts remote JSON-RPC requests and directly forwards attacker-supplied text into the local OpenClaw agent, effectively exposing the host's agent functionality over the network. In this skill context, that is especially dangerous because the bridge can enable untrusted remote agents to drive a local agent that may have broader tools, data access, or side effects than the A2A wrapper suggests.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"[A2A] Received: {text}")
        
        try:
            result = subprocess.run(
                ['openclaw', 'agent', '--agent', 'main', '--message', text, '--json'],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The startup log prints the full bearer token to stdout, which can leak secrets into terminal history, logs, process supervisors, container logs, or monitoring systems. Anyone who obtains that token can authenticate to the exposed A2A service and remotely invoke the local agent.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The manifest advertises broad, unconstrained capabilities such as general conversation, task execution, and various operations without clearly defining limits, authorization requirements, or safety boundaries. In an A2A context, vague capability descriptions increase the risk that remote agents or users will over-trust the service and invoke sensitive actions that were not clearly disclosed or scoped.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The manifest explicitly exposes an "execute" skill that can run shell commands and process files, but it provides no warning about the potential for system modification, data access, or destructive side effects. Because this is an A2A service intended for remote agent-to-agent use, under-disclosing system-impacting behavior is especially dangerous: other agents may invoke it without sufficient safeguards, creating a path to remote command execution and sensitive file abuse.

Static analysis

No suspicious patterns detected.