Back to skill

Security audit

Openclaw Web Automation

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a public webpage automation helper, but it does not enforce its stated public-site-only network boundary.

Review this skill before installing if your runtime can reach internal services. It should be used only in an environment where unrestricted outbound requests are acceptable, or after adding validation that allows only http/https public destinations and blocks localhost, private IP ranges, link-local metadata endpoints, unsafe redirects, and unexpected automation scripts.

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

T09 · Insecure Skill Coding Practices

Warning
Location
manifest.json:9
Finding
Unrestricted Network Scope Without Public-Address Validation## Vulnerability Details **File Location**: `manifest.json:9-12` **Related Locations**: `runner.py:16-24`, `schemas/input.json:5-10` **Vulnerability Type**: Server-Side Request Forgery (SSRF) / Missing Network-Destination Validation **Risk Level**: Medium ### Vulnerable Code `manifest.json:9-12`: ```json "permissions": { "browser": false, "network_domains": ["*"] } ``` `runner.py:16-24`: ```python query = str(inputs.get("query", "")) if not query: return {"ok": False, "error": "missing 'query' in inputs"} parsed = parse_query_to_run(query) engine = AutomationEngine(_REPO_ROOT) script_dir = resolve_script_dir(_REPO_ROOT, parsed.script_dir) result = engine.run(script_dir, parsed.inputs) ``` `schemas/input.json:5-10`: ```json "properties": { "query": { "type": "string", "description": "Natural-language request, e.g. 'check yahoo.com for the word finance'" } } ``` ### Technical Analysis The skill documentation limits its operation to public websites, but this boundary is not enforced by the supplied implementation: - The manifest authorizes network access to every domain through `network_domains: ["*"]`. - The input schema accepts an unrestricted natural-language string. - The runner passes the query through `parse_query_to_run()` and into `AutomationEngine.run()` without validating the resulting URL, scheme, hostname, resolved IP address, port, or redirects. - There are no explicit controls rejecting loopback, private, link-local, reserved, multicast, or cloud-metadata destinations. This creates a potential SSRF or confused-deputy condition if the delegated `openclaw_automation` implementation accepts arbitrary URLs. An attacker may be able to make the runtime issue requests to services that are inaccessible from the attacker's own network position. The external `openclaw_automation` package was not included in the reviewed project, so its internal protections could not be verified. The finding is therefore based on the absence ...[truncated 1479 chars]
Remediation
## Remediation Suggestions 1. **Restrict network permissions** - Replace `network_domains: ["*"]` with the narrowest practical domain allowlist. - If arbitrary public websites are a functional requirement, enforce a dedicated public-internet egress policy rather than unrestricted destination access. 2. **Validate parsed destinations** - Permit only `http` and `https`. - Reject URLs containing embedded credentials or malformed hostnames. - Restrict ports to those required by the skill. - Normalize hostnames before applying policy. 3. **Validate resolved addresses** - Resolve every hostname and reject loopback, private, link-local, multicast, unspecified, reserved, and other non-public address ranges for both IPv4 and IPv6. - Explicitly deny known cloud metadata destinations. - Perform this enforcement in the network request layer rather than relying solely on natural-language parsing. 4. **Secure redirects and DNS handling** - Revalidate the destination after every redirect. - Limit redirect depth. - Pin validated DNS resolutions where supported or otherwise mitigate DNS rebinding and time-of-check/time-of-use inconsistencies. 5. **Harden input controls** - Add a reasonable `maxLength` constraint to the `query` property. - Prefer extracting a structured URL field and validating it against a strict schema before execution. - Reject requests that cannot be unambiguously classified as public-site operations. 6. **Add security tests** - Test loopback, RFC 1918, link-local, IPv6-local, integer/hexadecimal IP representations, redirect chains, user-information URL syntax, alternate ports, and DNS-rebinding scenarios. - Verify that all such requests fail before any network connection is made.
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 (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill invokes a local Python script via a shell command, but the manifest does not declare any explicit tool or permission boundaries. That mismatch increases the risk that an agent may execute shell or environment-capable actions without clear scoping, review, or policy enforcement, especially because the command embeds user-controlled query text.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes a narrowly scoped capability—fetching public pages and extracting summaries or keywords—but grants network access to all domains via a wildcard. This violates least privilege and creates unnecessary attack surface: if the runner or downstream logic is abused, compromised, or later expanded, it could contact arbitrary endpoints rather than only the intended public targets.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The runner accepts an unrestricted natural-language query, converts it into a structured automation request, and immediately executes it via the automation engine. In a skill specifically designed for web automation, this creates a prompt-to-action path where ambiguous or adversarial user input can trigger unintended browsing or data retrieval behavior without an explicit confirmation, policy gate, or user-facing disclosure.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"--query",
        args.query,
    ]
    proc = subprocess.run(cmd, cwd=root, capture_output=True, text=True)
    if proc.returncode != 0:
        print(proc.stderr.strip() or proc.stdout.strip())
        return proc.returncode
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.