T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/_shop_product_common.py:15
- Finding
- Credential-Bearing Requests Can Be Redirected to an Untrusted or Plaintext Gateway<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_shop_product_common.py`, lines 15–20 and 59–89 **Vulnerability Type**: Unrestricted security-sensitive endpoint configuration **Risk Level**: High ### Vulnerable Code ```python API_BASE_URL = ( os.environ.get("LINKFOX_TOOL_GATEWAY") or os.environ.get("TIKTOK_SHOP_API_BASE_URL") or "https://tool-gateway.linkfox.com" ).rstrip("/") DEVELOPER_PROXY_ENDPOINT = f"{API_BASE_URL}/tiktokShop/developerProxy" ``` ```python def get_api_key() -> str: key = os.environ.get("LINKFOX_AGENT_API_KEY") or os.environ.get("LINKFOXAGENT_API_KEY") if not key: print("API Key 未配置", file=sys.stderr) sys.exit(1) return key def call_api(endpoint: str, params: dict) -> dict: api_key = get_api_key() data = json.dumps(params).encode("utf-8") req = Request( endpoint, data=data, headers={ "Authorization": api_key, "Content-Type": "application/json", "User-Agent": "LinkFox-Skill/1.0", "SESSION_ID": os.environ.get("SESSION_ID", ""), "MODE_ID": os.environ.get("MODE_ID", ""), "APP_NAME": os.environ.get("APP_NAME", ""), }, method="POST", ) try: with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) except HTTPError as e: body = e.read().decode("utf-8") if e.fp else "" return {"error": f"HTTP {e.code}: {e.reason}", "details": body} except URLError as e: return {"error": f"Connection failed: {e.reason}"} ``` ### Technical Analysis The Skill permits the developer-proxy destination to be replaced through either `LINKFOX_TOOL_GATEWAY` or `TIKTOK_SHOP_API_BASE_URL`. The selected URL is used without enforcing HTTPS, validating the hostname, or restricting the port and URL components. Every API request then transmits the following information to the selected destination: - The ...[truncated 2243 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require the gateway URL to use `https`. 2. Allowlist the documented production hostname, such as `tool-gateway.linkfox.com`. 3. Reject URLs containing user information, fragments, query strings, unexpected ports, or non-HTTPS schemes. 4. Prefer a fixed production endpoint rather than a general environment-controlled destination. 5. If custom gateways are required for development, require an explicit development-mode opt-in and prevent production credentials from being forwarded in that mode. 6. Validate the endpoint before retrieving the API key or constructing the request. 7. Use separate, narrowly scoped credentials for development and production environments. 8. Document the trust boundary for endpoint-related environment variables. Example validation approach: ```python from urllib.parse import urlparse ALLOWED_GATEWAY_HOSTS = {"tool-gateway.linkfox.com"} def validate_gateway_url(value: str) -> str: parsed = urlparse(value) if parsed.scheme != "https": raise ValueError("The LinkFox gateway must use HTTPS") if parsed.hostname not in ALLOWED_GATEWAY_HOSTS: raise ValueError("Untrusted LinkFox gateway host") if parsed.username or parsed.password or parsed.query or parsed.fragment: raise ValueError("Invalid gateway URL components") if parsed.port not in (None, 443): raise ValueError("Unexpected gateway port") return value.rstrip("/") ``` ]]>
