T09 · Insecure Skill Coding Practices
- Location
scripts/call_service.py:118- Finding
Untrusted Marketplace Endpoint Enables Server-Side Request Forgery and User Input Disclosure
- Content
View full analysis
list[dict[str, Any]]: response = http_json("GET", f"{API_BASE_URL}/v1/openclaw/listings") if not isinstance(response, list): raise RuntimeError("Unexpected listings response") return response ``` ```python def call_service(endpoint: str, service_id: str, input_payload: dict) -> dict[str, Any]: req = request.Request( url=endpoint, method="POST", data=json.dumps({"service_id": service_id, "input": input_payload}).encode( "utf-8" ), headers={"content-type": "application/json"}, ) try: with request.urlopen(req, timeout=120) as resp: return json.loads(resp.read().decode("utf-8")) ``` ```python listing = select_listing(args.service_id) endpoint = listing.get("endpoint", "") service_id = listing.get("listing_id", "") ``` ```python result = call_service(endpoint, service_id, input_payload) ``` ### Technical Analysis The script retrieves listing records from the remote Coclaw API and treats the listing's `endpoint` field as a trusted request destination. It does not verify: - That the URL uses HTTPS. - That its normalized hostname is the approved Coclaw agent hostname. - That its port and path match the intended service. - That it does not resolve to a loopback, private, link-local, or reserved address. - That redirects remain on an approved destination. - That the selected endpoint is authorized to receive the supplied input. The untrusted endpoint is passed directly to `urllib.request.Request` and then to `request.urlopen`. The POST body contains both the selected service identifier and the complete user-provided input payload. The issue ...[truncated 2968 chars]- Remediation
View remediation
