T09 · Insecure Skill Coding Practices
- Location
clawmot_skill.py:35- Finding
Bearer credentials and registration data can be redirected to an attacker-controlled API origin
- Content
View full analysis
Vulnerability Details
File Location:
clawmot_skill.py:35-72
Vulnerability Type: Unvalidated network destination for sensitive authenticated requests
Risk Level: HighVulnerable Code
python def _base() -> str: return retrieve("clawmot.base_url") or os.environ.get("CLAWMOT_BASE_URL", "https://clawmot.com") def _runtime_version() -> str: return retrieve("clawmot.agent_runtime_version") or "openclaw-2.x" def _auth_headers() -> dict[str, str]: jwt = retrieve("clawmot.jwt") if not jwt: raise PermissionError( "Not authenticated. Call clawmot_register(email) and clawmot_verify(...) first." ) return {"Authorization": f"Bearer {jwt}"} def _post(path: str, json: dict[str, Any] | None = None, *, auth: bool = True) -> dict[str, Any]: headers = _auth_headers() if auth else {} r = httpx.post(f"{_base()}{path}", json=json or {}, headers=headers, timeout=30) _raise(r) return r.json() def _get(path: str, params: dict[str, Any] | None = None, *, auth: bool = True) -> dict[str, Any]: headers = _auth_headers() if auth else {} r = httpx.get(f"{_base()}{path}", params=params or {}, headers=headers, timeout=30) _raise(r) return r.json() def _patch(path: str, json: dict[str, Any]) -> dict[str, Any]: r = httpx.patch(f"{_base()}{path}", json=json, headers=_auth_headers(), timeout=30) _raise(r) return r.json()Technical Analysis
The API base URL can be taken from either the mutable
clawmot.base_urlkey-value entry or theCLAWMOT_BASE_URLenvironment variable. The value is concatenated directly with API paths without validating its scheme, hostname, port, or relationship to the origin that issued the credentials.All authenticated request helpers then attach the stored 30-day JWT to this selected destination. The unauthenticated registration and verification methods also use the same ...[truncated 1495 chars]
- Remediation
View remediation
Remediation Suggestions
- Use a fixed HTTPS CLAWMOT origin by default.
- If self-hosting is required, validate the URL with a strict parser and reject non-HTTPS schemes, embedded credentials, unexpected ports, fragments, and malformed hosts.
- Maintain an explicit allowlist of approved API origins or require a separate trusted administrative setup step before accepting a custom origin.
- Bind each stored JWT and long-lived secret to the exact origin that issued it, and refuse to transmit credentials when the active origin changes.
- Require explicit user confirmation before migrating credentials or registering against a non-default service.
- Disable cross-origin redirects for requests carrying authentication headers.
- Add tests proving that HTTP, localhost, link-local, private-network, and unapproved public destinations are rejected.
