T05 · Unauthorized Access and Privilege Escalation
- Location
clawstatus.py:2742- Finding
Unauthenticated Administrative APIs Permit OpenClaw Configuration Changes and Cron Control
- Content
View full analysis
Flask: app = Flask(__name__) # Requirement: page works out of box, no token input needed required_token = None ``` The authorization helper permits every request when no token is configured: ```python def _is_authorized(required_token: Optional[str]) -> bool: if not required_token: return True got = _token_from_request() return bool(got and got == required_token) def _require_auth(required_token: Optional[str]): if _is_authorized(required_token): return None return jsonify({"error": "unauthorized", "valid": False}), 401 ``` State-changing routes rely on this ineffective check: ```python @app.post("/api/agents//model") def api_agent_model_update(agent_id: str): auth_resp = _require_auth(required_token) if auth_resp is not None: return auth_resp payload = request.get_json(silent=True) or {} model_id = str(payload.get("model") or "").strip() if not model_id: return jsonify({"error": "missing model"}), 400 try: result = _update_agent_model(agent_id, model_id) except KeyError: return jsonify({"error": "agent not found", "agentId": agent_id}), 404 except ValueError: return jsonify({"error": "invalid model", "model": model_id}), 400 except PermissionError as e: return jsonify({"error": f"write failed: {e}"}), 500 except OSError as e: return jsonify({"error": f"write failed: {e}"}), 500 return jsonify(result) @app.post("/api/crons//model") def api_cron_model_update(job_id: str): auth_resp = _require_a ...[truncated 4863 chars]- Remediation
View remediation
Flask: app = Flask(__name__) required_token = _load_auth_token() ``` 2. Fail closed when binding to any non-loopback address. Refuse startup on `0.0.0.0` or an external address unless strong authentication is configured. 3. Separate read-only monitoring permissions from administrative permissions. Administrative routes should require a distinct, higher-privilege credential. 4. Disable mutation endpoints by default. Require an explicit option such as `--enable-admin-api` before registering routes that edit models, execute jobs, delete jobs, or restart services. 5. Add CSRF protection to browser-accessible state-changing routes. Use unpredictable CSRF tokens and restrictive `SameSite` cookies if session-based authentication is introduced. 6. Do not accept authentication tokens through URL query parameters because URLs may be stored in browser history, proxy logs, and access logs. 7. Compare secret tokens using `hmac.compare_digest()` and enforce transport encryption through a secured reverse proxy when remote access is required. 8. Apply rate limits and record authenticated audit events for every configuration change, job execution, job deletion, and service restart. 9. Bind to `127.0.0.1` by default and update the documentation to recommend SSH tunneling or an authenticated TLS reverse proxy for remote access. ]]>
