T09 · Insecure Skill Coding Practices
Error
- Location
- skills/smyx_common/scripts/util.py:568
- Finding
- Authentication Credentials Can Be Forwarded to Arbitrary Request Origins and Are Persisted in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `skills/smyx_common/scripts/util.py:568-608, 642`; related plaintext storage at `skills/smyx_common/scripts/dao.py:460-462` **Vulnerability Type**: Unrestricted credential forwarding and plaintext token storage **Risk Level**: High ### Vulnerable Code ```python if not url.startswith("https://") and not url.startswith("http://"): url = cls.BASE_URL + url headers['App-Id'] = ConstantEnum.APP__ID if not (ApiEnum.API_SECRET_KEY or ConstantEnum.CURRENT__USER_NAME or ConstantEnum.CURRENT__OPEN_ID): OpenIdUtil.resolve_current_open_id(use_current=False) current__user_name = ( ApiEnum.API_SECRET_KEY or ConstantEnum.CURRENT__USER_NAME or ConstantEnum.CURRENT__OPEN_ID ) found_user = None if (not ApiEnum.TOKEN or not ApiEnum.OPEN_TOKEN) and current__user_name: try: from .dao import UserDao, User user_dao = UserDao() found_user = user_dao.get_by_username(current__user_name) if found_user: ApiEnum.TOKEN = found_user.token ApiEnum.OPEN_TOKEN = found_user.open_token current__user_name = found_user.username if not ApiEnum.TOKEN or not ApiEnum.OPEN_TOKEN: new_current_user = _get_or_create_user(current__user_name) if new_current_user: ApiEnum.TOKEN = new_current_user.get("token") ApiEnum.OPEN_TOKEN = new_current_user.get("openToken") current_user_info = new_current_user.get("userInfo") if current_user_info: current_user_info["token"] = new_current_user.get("token") current_user_info["openToken"] = new_current_user.get( "openToken") user_model = User.load(current_user_info) user = user_dao.save( user_model ) except Exception as e: CommonUtil.trace_exception_stack(e) raise ...[truncated 3302 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce a strict allowlist of trusted HTTPS origins before attaching credentials: - Parse URLs with `urllib.parse.urlsplit`. - Require `scheme == "https"`. - Compare the normalized hostname and port against configured first-party origins. - Reject user-info components, unexpected ports, redirects to untrusted origins, and malformed hostnames. 2. Separate authenticated and unauthenticated clients: - Use a dedicated first-party API client that always targets a fixed base URL. - Use a separate generic client for remote media URLs that never receives authentication headers. 3. Do not attach credentials merely because a URL is absolute. Add authentication only after confirming that the destination matches the intended API origin. 4. Disable automatic forwarding of sensitive headers across redirects, or disable redirects and validate every redirect destination explicitly. 5. Reject plain HTTP for all authenticated requests. 6. Store tokens in an operating-system credential manager or encrypted secret store. If SQLite storage is unavoidable: - Encrypt token values using a key stored outside the database. - Restrict database and parent-directory permissions to the current user. - Define token expiration and rotation behavior. - Remove stale tokens when authentication fails or the Skill is uninstalled. 7. Add tests proving that credentials are absent when requesting an unknown host, alternate port, plain HTTP URL, or cross-origin redirect. ]]>
