Back to skill

Security audit

极鲸云Shopee商品搜索

Security checks for vulnerabilities and agentic risk

Overview

This skill does useful Shopee research through GeekBI, but its credential handling and endpoint controls need review before installation.

Install only if you are comfortable with this skill storing GeekBI login tokens locally and making authenticated requests from its Python scripts. Prefer using only the default GeekBI endpoint, avoid passing custom base URLs, and consider clearing .geekbi auth state after use.

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

Error
Location
scripts/geekbi_auth.py:698
Finding
Unrestricted API Base URL Allows Sensitive Authentication Data to Be Sent to Untrusted Hosts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:698-721`; exposed through `scripts/shopee_goods_search.py:58-67`, `scripts/shopee_goods_info.py:35-42`, and `scripts/shopee_site_list.py:77-83` **Vulnerability Type**: Unvalidated authentication destination and insecure transport **Risk Level**: High ### Complete Vulnerable Code Snippet ```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"] = authorization request = Request( url, data=body, headers=request_headers, method=method, ) try: with urlopen(request, timeout=timeout) as response: response_payload = _read_json_response(response) _raise_action_if_needed(response_payload) return response_payload ``` The authentication exchange uses the same unrestricted base URL: ```python endpoint = f"{base_url.rstrip('/')}{TOKEN_ENDPOINT}" try: response = _post_json( endpoint, {"deviceCode": pending["deviceCode"]}, timeout, ) ``` Each business command exposes that value directly to the caller. For example: ```python 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 ) ``` Equivalent unrestricted `--base-url` arguments are present in the product-detail and site-list commands. ### Technical Analysis The defaul ...[truncated 3251 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` from production-facing commands if endpoint customization is not essential. 2. If customization is required, enforce an explicit allowlist of complete origins, such as exactly `https://openapi.geekbi.com`. 3. Parse URLs with `urllib.parse.urlsplit()` and reject: - Any scheme other than HTTPS; - Unexpected hostnames or ports; - Embedded user information; - Fragments or malformed authority components. 4. Build API URLs from a validated origin rather than concatenating raw strings. 5. Validate `jumpUrl` separately and only display links using an approved HTTPS origin. 6. Ensure redirects cannot cause authentication headers or device codes to be forwarded to a different origin. Prefer disabling redirects for authenticated requests or validating every redirect destination. 7. Separate test endpoint support from production code. Test overrides should require an explicit development mode and should not have access to production authentication state. 8. Add automated tests covering HTTP URLs, attacker-controlled hosts, malformed URLs, alternate ports, user-information tricks, and cross-origin redirects. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geekbi_auth.py:68
Finding
Bearer Tokens Are Unnecessarily Mirrored into Skill and Working Directories<![CDATA[ ## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:68-101`, with token persistence at `scripts/geekbi_auth.py:368-383` and `scripts/geekbi_auth.py:637-648` **Vulnerability Type**: Excessive local secret replication **Risk Level**: Medium ### Complete Vulnerable Code Snippet The authentication module defines three separate storage locations: ```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"), ) stores = [] seen_paths = set() for store in candidates: path_key = os.path.normcase(os.fspath(store.path)) if path_key in seen_paths: continue seen_paths.add(path_key) stores.append(store) return tuple(stores) ``` The normalized authentication state is then written to every writable store: ```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) ``` That state contains the bearer token: ```python def save_token(latest): latest_server = latest["servers"].get(server_key) i ...[truncated 3050 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store authentication state in exactly one user-scoped configuration location. 2. Do not write bearer tokens into the Skill installation directory or current working directory. 3. Prefer an operating-system credential manager or keychain for the bearer token; keep only non-sensitive metadata in JSON. 4. Fail securely if restrictive permissions cannot be established instead of silently continuing. 5. On POSIX systems: - Create the directory with mode `0700`; - Open files atomically with mode `0600`; - Verify ownership and final permissions after replacement; - Reject symlinks and unexpected file types. 6. On Windows and other non-POSIX platforms, apply platform-native access controls rather than skipping permission enforcement. 7. Record the exact credential-store location independently so logout can remove the token even when the process runs from a different working directory. 8. Revoke tokens server-side when authentication state is cleared, if the API supports revocation. 9. Add migration logic that detects and securely removes legacy copies from Skill and workspace directories. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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
87% confidence
Finding
The skill instructs the agent to run local scripts and make live queries, which implies shell, file-read, and network capabilities, but no permissions are declared. That mismatch can bypass expected review and consent controls, making it harder to constrain what the skill is allowed to access or execute if the implementation changes or is abused.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The auth state is stored under a hard-coded "temu-research-skill" namespace even though this skill is for Shopee product search. That can cause credential/state confusion across skills that share the same host environment, potentially leading to unintended token reuse, logout interference, or reading another skill's auth state if both trust the same file layout.

Static analysis

No suspicious patterns detected.