T09 · Insecure Skill Coding Practices
- Location
scripts/common.py:84- Finding
Bearer Credentials and Document Contents May Be Transmitted over Cleartext HTTP
- Content
View full analysis
Vulnerability Details
File Location:
scripts/common.py:84-92, 165-184;scripts/upload.py:62-80, 119-131
Vulnerability Type: Cleartext transmission of sensitive information
Risk Level: HighComplete Code Snippet
python # scripts/common.py:84-92 def resolve_base_url(cli_base_url: str | None = None) -> str: base_url = (cli_base_url or "").strip() or _require_env_var(RAGFLOW_API_URL_ENV) parsed = urllib.parse.urlsplit(base_url) if not parsed.scheme or not parsed.netloc: raise ConfigError( f"Invalid {RAGFLOW_API_URL_ENV}. Use an absolute URL such as http://127.0.0.1:9380." ) return base_url.rstrip("/")python # scripts/common.py:165-184 def request_json( url: str, api_key: str, *, method: str = "GET", body: bytes | None = None, content_type: str | None = None, accept: str = "application/json", ) -> dict[str, Any]: headers = {"Authorization": f"Bearer {api_key}"} if accept: headers["Accept"] = accept if content_type: headers["Content-Type"] = content_type request_obj = urllib.request.Request(url, headers=headers, data=body, method=method) try: with urllib.request.urlopen(request_obj, timeout=HTTP_TIMEOUT) as response: return decode_json_response(response.read())python # scripts/upload.py:62-80 def _build_multipart(file_paths: list[str]) -> tuple[str, bytes]: boundary = "----OpenClawBoundary" + uuid.uuid4().hex body = bytearray() for file_path in file_paths: filename = os.path.basename(file_path) mime = mimetypes.guess_type(filename)[0] or "application/octet-stream" with open(file_path, "rb") as file_obj: content = file_obj.read() body.extend(f"--{boundary}\r\n".encode()) body.extend( f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'.encode() ) body.extend(f"Content-Type: {mime}\ ...[truncated 3806 chars]- Remediation
View remediation
Remediation Suggestions
- Require HTTPS for all non-loopback RAGFlow endpoints:
python def resolve_base_url(cli_base_url: str | None = None) -> str: base_url = (cli_base_url or "").strip() or _require_env_var(RAGFLOW_API_URL_ENV) parsed = urllib.parse.urlsplit(base_url) if parsed.scheme not in {"https", "http"} or not parsed.netloc: raise ConfigError("RAGFLOW_API_URL must be an absolute HTTP(S) URL.") hostname = (parsed.hostname or "").lower() loopback_hosts = {"localhost", "127.0.0.1", "::1"} if parsed.scheme != "https" and hostname not in loopback_hosts: raise ConfigError("HTTPS is required for non-loopback RAGFlow endpoints.") return base_url.rstrip("/")-
Prefer HTTPS even for local deployments when the service crosses container, virtual-machine, or host boundaries. Treat container-network and private-network addresses as remote rather than loopback.
-
If compatibility requires cleartext HTTP, place it behind an explicit option such as
--allow-insecure-http, default it to disabled, and emit a prominent warning. Do not infer safety merely from RFC1918/private addressing. -
Update documentation and validation messages so the normal example uses an HTTPS URL. Clearly state that bearer credentials and uploaded documents are transmitted to the configured endpoint.
-
Use short-lived, narrowly scoped API credentials where RAGFlow supports them. Separate read-only credentials for list/status/search operations from credentials capable of uploads, updates, and deletion.
-
Ensure TLS certificate verification remains enabled. Do not introduce unverified SSL contexts as a workaround for private certificates; configure an appropriate trusted CA bundle instead.
-
Consider adding automated tests that verify:
https://endpoints are accepted.- non-loopback
http://endpoints are rejected by default. - loopback HTTP is accepted only under the documented policy.
- unsupported schemes such as ...[truncated 37 chars]
