T09 · Insecure Skill Coding Practices
Error
- Location
- claw-config.py:546
- Finding
- Unrestricted Documentation URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `claw-config.py:458-461` and `claw-config.py:546-550` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through unrestricted URL fetching **Risk Level**: High ### Complete Vulnerable Code ```python try: p = subprocess.run( ["curl", "-fsSL", "--max-time", "10", url], capture_output=True, text=True, timeout=12, ) ``` ```python # full URL or slug if topic.startswith("http://") or topic.startswith("https://"): url = topic else: slug = topic.lstrip("/") if slug.endswith(".md"): slug = slug[:-3] url = f"{DOCS_BASE}/{slug}.md" ``` ### Technical Analysis The `docs` subcommand accepts any URL beginning with `http://` or `https://` and passes it directly to `curl`. There is no restriction requiring the destination to be `docs.openclaw.ai`, even though retrieving official OpenClaw documentation is the declared reason for network access. There is also no validation of: - The destination hostname - The resolved IP address - Loopback, link-local, private, or reserved address ranges - Redirect destinations - Whether HTTPS is used The `-L` option instructs `curl` to follow redirects. Consequently, even an initially permitted-looking external destination could redirect the request to an internal service. The request does not automatically attach OpenClaw configuration values, credentials, tokens, or arbitrary environment variables. Nevertheless, arbitrary network access exceeds the minimum privilege required to retrieve official documentation. ### Attack Path 1. An attacker or untrusted instruction causes the Agent to invoke a command such as: ```bash claw-config docs http://127.0.0.1:PORT/internal ``` or: ```bash claw-config docs http://169.254.169.254/metadata-path ``` 2. `cmd_docs()` accepts the full URL without validating its hostname or resolved address. 3. `_fetch_docs()` executes `curl -fsSL` against the supplied destination. 4 ...[truncated 903 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove support for arbitrary full URLs. Accept only documentation slugs and construct the URL internally under `https://docs.openclaw.ai/`. 2. Parse destinations with `urllib.parse.urlsplit()` and require: - Scheme exactly equal to `https` - Hostname exactly equal to `docs.openclaw.ai` - No embedded credentials - An expected or empty port 3. Disable redirects or validate every redirect destination against the same restrictions. 4. Resolve the destination hostname and reject loopback, link-local, private, multicast, unspecified, and reserved IP addresses. 5. Do not rely solely on string-prefix checks such as `url.startswith(DOCS_BASE)`, because hostname confusion and redirect behavior can bypass weak checks. 6. Consider replacing the external `curl` process with a narrowly configured HTTP client that enforces destination and response-size policies. 7. Add a maximum response size to prevent an attacker-controlled endpoint from causing excessive memory or disk use. 8. Add tests covering localhost, private addresses, cloud metadata addresses, alternate ports, malformed hostnames, and cross-host redirects. ]]>
