T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/limesurvey_client.py:31
- Finding
- Sensitive credentials and survey data may be transmitted without enforced TLS<![CDATA[ ## Vulnerability Details **File Location**: `scripts/limesurvey_client.py:31-71` and `scripts/limesurvey_client.py:94` **Vulnerability Type**: Cleartext transmission of sensitive information due to missing HTTPS enforcement **Risk Level**: Medium ### Vulnerable Code ```python def __init__(self, url): """ Initialize the LimeSurvey client Args: url: Full URL to the RemoteControl endpoint Example: https://example.com/index.php/admin/remotecontrol """ self.url = url self.request_id = 0 def call(self, method, *params): """ Call a RemoteControl API method """ self.request_id += 1 payload = { "jsonrpc": "2.0", "method": method, "params": list(params), "id": self.request_id } data = json.dumps(payload).encode('utf-8') req = urllib_request.Request( self.url, data=data, headers={ 'Content-Type': 'application/json', 'Connection': 'Keep-Alive' } ) try: with urllib_request.urlopen(req) as response: result = json.loads(response.read().decode('utf-8')) ``` Authentication credentials are passed through the same unrestricted request method: ```python result = self.call('get_session_key', username, password, plugin) ``` ### Technical Analysis The client accepts the endpoint URL without validating its scheme or requiring HTTPS. The `call()` method serializes every JSON-RPC parameter and sends it directly to that endpoint. For `get_session_key`, those parameters include the LimeSurvey username and password. Subsequent requests can contain session keys, participant names and email addresses, participant tokens, survey responses, imported survey contents, and administrative modification requests. If `LIMESURVEY_URL` uses `http://`, these values can travel across the network without transport encryption. Base64 processing shown elsewhere in the project is part of LimeSu ...[truncated 2202 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse and validate the configured endpoint before storing or using it: ```python from urllib.parse import urlparse parsed = urlparse(url) if parsed.scheme != "https": raise ValueError("LimeSurvey endpoint must use HTTPS") if not parsed.hostname: raise ValueError("LimeSurvey endpoint must include a valid hostname") if parsed.username or parsed.password: raise ValueError("Credentials must not be embedded in the endpoint URL") ``` 2. If cleartext HTTP is required for isolated local development, reject it by default and require an explicit insecure option restricted to loopback addresses. Display a prominent warning when that option is enabled. 3. Prevent HTTPS-to-HTTP downgrade redirects. Use a redirect handler that rejects any redirect whose destination is not HTTPS. 4. Add a finite connection and response timeout to avoid indefinite blocking: ```python with urllib_request.urlopen(req, timeout=30) as response: ... ``` 5. Continue using the platform's default certificate validation. Do not add an unverified SSL context or disable hostname verification. 6. Replace documentation examples that use `admin` with a dedicated service-account name. Require the account to have only the survey and API permissions necessary for the intended command set. 7. Restrict the RemoteControl endpoint through network controls where possible, rotate exposed credentials, and invalidate existing sessions if HTTP transmission may already have occurred. ]]>
