Back to skill

Security audit

极鲸云Shopee类目搜索

Security checks for vulnerabilities and agentic risk

Overview

The skill’s Shopee research purpose is coherent, but it stores login tokens in multiple plaintext locations and can be pointed at untrusted API/auth URLs.

Review this skill before installing. Use it only if you trust the GeekBI workflow, avoid passing custom --base-url values, verify any login link before opening it, and be aware that authentication state may be written as plaintext into multiple local directories.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geekbi_auth.py:53
Finding
Bearer Tokens Are Mirrored Across Multiple Plaintext State Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:53-71`, `scripts/geekbi_auth.py:371-383`, and `scripts/geekbi_auth.py:637-652` **Vulnerability Type**: Excessive plaintext credential storage **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"), ) ``` ```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) ``` ```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(latest_server) latest_server["accessToken"] = access_token latest_server["accessTokenExpiresAt"] = now + max(0, expires_in - 30) latest_server.pop("pending", None) re ...[truncated 2295 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Keep only one authentication-state location, preferably the dedicated per-user configuration directory. 2. Do not write bearer tokens into the Skill installation directory or current workspace. 3. Prefer an operating-system credential facility such as Windows Credential Manager, macOS Keychain, or Secret Service on Linux. 4. If file storage remains necessary: - Encrypt token material at rest using a key protected by the operating system. - Apply explicit Windows ACLs in addition to POSIX permission modes. - Reject state files owned by another user or having unsafe permissions. - Avoid following symbolic links when opening or replacing credential files. 5. Rename the configuration namespace from `temu-research-skill` to a unique Shopee-specific identifier. 6. Add a migration routine that removes legacy token copies from the Skill and workspace directories after securely importing or invalidating them. 7. Ensure logout reports deletion failures instead of silently ignoring them, and revoke the server-side token where supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/shopee_goods_search.py:59
Finding
Unrestricted API Origin Allows Cleartext Data Transmission and Malicious Authentication Challenges<![CDATA[ ## Vulnerability Details **File Location**: `scripts/shopee_goods_search.py:59-67`, with equivalent behavior in `scripts/shopee_site_list.py:77-82`, `scripts/shopee_category_info.py:36-42`, and `scripts/shopee_category_list.py:36-42` **Vulnerability Type**: Unvalidated network destination and transport scheme **Risk Level**: Medium ### Vulnerable Code ```python def main(): parser = argparse.ArgumentParser(description="查询 Shopee 商品并输出 JSON") parser.add_argument("--base-url", default=DEFAULT_BASE_URL) parser.add_argument("--param", action="append", default=[], help="查询条件,格式为 名称=值") parser.add_argument("--timeout", type=float, default=30) args = parser.parse_args() try: params = parse_params(args.param) payload = authenticated_json_request( build_url(args.base_url, ENDPOINT, params), args.base_url, args.timeout ) ``` The supplied origin is used directly to construct authentication and API requests: ```python def complete_pending_login(base_url, timeout): payload = _load_state() server_key = _server_key(base_url) server = payload["servers"].get(server_key) if not isinstance(server, dict): return False now = int(time.time()) changed = _clear_expired(server, now) pending = server.get("pending") if not isinstance(pending, dict): if changed: _persist_expiry_cleanup(server_key, now) return False endpoint = f"{base_url.rstrip('/')}{TOKEN_ENDPOINT}" try: response = _post_json(endpoint, {"deviceCode": pending["deviceCode"]}, timeout) ``` ```python def authenticated_json_request( url, base_url, timeout, *, method="GET", body=None, headers=None, ): complete_pending_login(base_url, timeout) request_headers = _api_headers() if headers: request_headers.update(headers) authorization = _authorization_header(base_url) if authorization: request_headers["token"] = ...[truncated 3009 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the public `--base-url` option from production query scripts. 2. If endpoint overrides are required for controlled testing, gate them behind an explicit development mode that is disabled by default. 3. Validate the destination with a structured URL parser and require: - Scheme exactly equal to `https`. - Hostname exactly equal to `openapi.geekbi.com`, or membership in a narrowly defined allowlist. - No embedded username or password. - No fragments. - Only approved ports and base paths. 4. Canonicalize the validated origin before using it as an authentication-state key. 5. Validate every server-provided `jumpUrl` against a separate allowlist of trusted HTTPS authentication origins before displaying it. 6. Do not automatically follow redirects to a different origin. Revalidate the destination after every redirect and never forward authentication headers cross-origin. 7. Add automated tests covering cleartext HTTP, lookalike domains, embedded credentials, nonstandard ports, malformed URLs, and malicious authentication challenge URLs. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill instructs the agent to invoke local scripts and read reference files, which implies shell execution, file access, and likely network access, but the skill declares no permissions or capability boundaries. This creates an authorization gap: an agent or runtime may execute higher-risk actions without explicit least-privilege review, increasing the chance of unintended data access or command execution abuse if the skill is triggered in the wrong context.

Vague Triggers

Medium
Confidence
81% confidence
Finding
The activation text is broad and topic-driven ('Shopee category tree', 'category ID', 'category research', 'track analysis', 'category selection'), which can cause the skill to activate in loosely related conversations. Because the skill then directs the agent to run scripts and query external data, overbroad triggering expands the circumstances under which privileged actions may occur and raises the risk of unintended tool use or data exposure.

Static analysis

No suspicious patterns detected.