T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/main.py:82
- Finding
- Configurable API Base URL Enables Credential and Sensitive Document Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:82`, `scripts/main.py:111-138` **Vulnerability Type**: Unrestricted network destination for sensitive data **Risk Level**: High ### Vulnerable Code ```python config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1') ``` ```python api_base = config['SCNET_API_BASE'] api_key = config['SCNET_API_KEY'] url = f"{api_base}/ocr/recognize" headers = { 'Authorization': f'Bearer {api_key}' } try: with open(file_path, 'rb') as f: files = { 'file': (os.path.basename(file_path), f, mime_type) } data = { 'ocrType': ocr_type, 'channelTag': "scnetSkills" } response = requests.post( url, headers=headers, data=data, files=files, timeout=60 ) ``` ### Technical Analysis The script reads `SCNET_API_BASE` from the local configuration and uses it directly to construct the upload destination. It performs no validation of: - The URL scheme - The destination hostname - The destination port - The expected API path - Whether transport encryption is required Consequently, the configured value can point to an arbitrary host, including a plaintext HTTP endpoint. The request includes both the bearer API credential and the complete user-selected birth-certificate file. This behavior conflicts with the network permission declared in `skill.yaml`, which lists only: ```text https://api.scnet.cn/api/llm/v1/ocr/recognize ``` Birth certificates can contain newborn information, parental identity numbers, addresses, medical details, and certificate identifiers. Sending this material to an unrestricted destination exceeds the minimum network privilege represented by the manifest. ### Attack Path 1. An attacker gains the ability to alter `config/.env`, or persuades the user to apply an unsafe configuration. 2. The attacker sets `SCNET_API_BASE` to an attacke ...[truncated 1245 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `SCNET_API_BASE` configurability if the Skill is intended to communicate only with the documented Scnet service. 2. Use a fixed endpoint: ```python OCR_ENDPOINT = "https://api.scnet.cn/api/llm/v1/ocr/recognize" ``` 3. If endpoint customization is operationally necessary: - Parse the URL with `urllib.parse.urlparse`. - Require the `https` scheme. - Enforce an explicit hostname allowlist. - Enforce the expected API path. - Reject embedded credentials, fragments, and unexpected ports. 4. Disable redirects with `allow_redirects=False`, or independently validate every redirect destination before following it. 5. Never send the bearer credential to a destination that has not passed validation. 6. Align `skill.yaml`, `SKILL.md`, and runtime behavior so the declared network permission exactly matches all permitted destinations. 7. Add automated tests proving that HTTP URLs, unapproved domains, malformed URLs, and unexpected ports or paths are rejected. ]]>
