T09 · Insecure Skill Coding Practices
- Location
scripts/query_telegram.py:18- Finding
Plaintext Transmission of Sensitive Telegram Queries and API Credentials
- Content
View full analysis
Vulnerability Details
File Location:
scripts/query_telegram.py:18-50; related insecure configuration examples appear inSKILL.md:20-21andskill.yaml:18-20
Vulnerability Type: Plaintext transmission of sensitive data
Risk Level: MediumVulnerable Code
python # Read configuration from environment variables defined in SKILL.md base_url = os.environ.get("LIFEQUERY_BASE_URL", "http://localhost:3134/v1").rstrip("/") api_key = os.environ.get("LIFEQUERY_API_KEY", "") url = f"{base_url}/chat/completions" headers = { "Content-Type": "application/json" } # Support optional API key authentication if api_key: headers["Authorization"] = f"Bearer {api_key}" # LifeQuery uses an OpenAI-compatible API endpoint structure data = { "model": "lifequery", "messages": [ {"role": "user", "content": args.query} ], "temperature": 0.0, "stream": False } try: req = urllib.request.Request( url, data=json.dumps(data).encode("utf-8"), headers=headers, method="POST" ) with urllib.request.urlopen(req) as response: result = json.loads(response.read().decode("utf-8"))The documentation explicitly permits an unencrypted remote endpoint:
markdown - `LIFEQUERY_BASE_URL`: Base URL of your LifeQuery instance (e.g., `http://localhost:3134/v1` or `http://your-server:80/v1`) - `LIFEQUERY_API_KEY`: Optional API key if protectedTechnical Analysis
The base URL is entirely controlled through the
LIFEQUERY_BASE_URLenvironment variable, and the script does not enforce HTTPS for non-loopback destinations. When an API key is configured, it is placed in an HTTPAuthorization: Bearerheader. The user's Telegram-history query is also placed in the request body.Although
urllib.request.urlopenperforms certificate validation for HTTPS URLs, it provides no transport confidentiality or server authentication when the configured URL uses HTTP. The documented `http://y ...[truncated 1831 chars]- Remediation
View remediation
Remediation Suggestions
- Require
https://for every non-loopback LifeQuery endpoint. - Permit plaintext HTTP only for explicitly recognized loopback addresses such as
localhost,127.0.0.1, and::1. - Reject startup or request execution when an API key would be transmitted over HTTP.
- Replace the documented remote example with an HTTPS URL, such as
https://your-server.example/v1. - Parse and validate the URL with
urllib.parse.urlparserather than relying on string-prefix checks. Reject missing schemes, embedded credentials, and unsupported schemes. - Preserve normal TLS certificate and hostname verification. Do not introduce an unverified SSL context as a compatibility workaround.
- Consider an explicit opt-in override only for controlled development environments, accompanied by a prominent warning and disabled by default.
- Use narrowly scoped, short-lived API credentials where supported, and rotate any credential previously sent through a remote HTTP endpoint.
A suitable validation policy is:
python from urllib.parse import urlparse import ipaddress parsed = urlparse(base_url) host = parsed.hostname is_loopback = host == "localhost" if host and not is_loopback: try: is_loopback = ipaddress.ip_address(host).is_loopback except ValueError: pass if parsed.scheme != "https" and not (parsed.scheme == "http" and is_loopback): raise ValueError( "LIFEQUERY_BASE_URL must use HTTPS unless it targets a loopback address." ) if api_key and parsed.scheme != "https": raise ValueError("Refusing to send LIFEQUERY_API_KEY over plaintext HTTP.")- Require
