T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/geekbi_auth.py:69
- Finding
- Bearer Tokens Are Persisted in Multiple Unnecessary Locations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:69-89`, with token persistence at `scripts/geekbi_auth.py:357-376` and `scripts/geekbi_auth.py:631-652` **Vulnerability Type**: Excessive credential storage and authentication-state namespace collision **Risk Level**: Medium ### Vulnerable Code ```python def _user_config_state_path(): return _absolute_path( user_config_path("GeekBI", appauthor=False, ensure_exists=True) / "temu-research-skill" / AUTH_FILE_NAME ) def _skill_state_path(): return _absolute_path(Path(__file__).parent.parent / AUTH_STATE_DIR / AUTH_FILE_NAME) def _workspace_state_path(): return _absolute_path(Path(os.getcwd()) / AUTH_STATE_DIR / AUTH_FILE_NAME) def _resolve_stores(): candidates = ( ResolvedStore(_user_config_state_path(), "user-config-directory"), ResolvedStore(_skill_state_path(), "skill-directory"), ResolvedStore(_workspace_state_path(), "working-directory"), ) ``` The resolved stores are all written when authentication state changes: ```python def _write_state_files(stores, payload): normalized = _normalize_state(payload) errors = [] written = 0 for store in stores: try: _write_state_file(store, normalized) written += 1 except OSError as error: errors.append(f"{store.kind}: {_storage_probe_reason(error)}") if written == 0: reason = ";".join(errors) or "登录状态目录不可用" raise OSError(reason) ``` The persisted state includes the bearer token: ```python def save_token(latest): latest_server = latest["servers"].get(server_key) if not isinstance(latest_server, dict): return False, False latest_pending = latest_server.get("pending") if not isinstance(latest_pending, dict): return False, False if latest_pending.get("deviceCode") != pending.get("deviceCode"): return False, False _remove_access_token(l ...[truncated 2967 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Persist authentication state only in a dedicated user configuration directory, for example: ```python user_config_path("GeekBI", appauthor=False, ensure_exists=True) \ / "geekbi-shopee-shop-search-skill" \ / AUTH_FILE_NAME ``` 2. Remove `_skill_state_path()` and `_workspace_state_path()` from `_resolve_stores()`. 3. Correct the `temu-research-skill` namespace to a unique Shopee Skill identifier. 4. Prefer operating-system credential facilities such as Keychain, Credential Manager, or Secret Service for bearer tokens. 5. If file storage is required, fail closed when restrictive permissions cannot be established instead of silently ignoring permission-setting failures. 6. Migrate existing state by reading legacy locations once, writing the token into the secure canonical store, and securely deleting all legacy copies. 7. Avoid returning exact credential-storage paths in normal user-visible output unless diagnostic disclosure is explicitly requested. ]]>
