Back to skill

Security audit

极鲸云Coupang商品搜索

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real Coupang data-query tool, but it stores login tokens in too many places and allows an overly flexible API destination.

Review this skill before installing if you will authenticate with GeekBI. Use only the default GeekBI API origin, do not follow unexpected login links, and be aware that login state may be written to both the skill installation and your current workspace as .geekbi/agent-auth.json.

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/coupang_goods_search.py:64
Finding
Unrestricted API Origin Permits Insecure Authentication and Attacker-Controlled Login Flows<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/coupang_goods_search.py:64-73` - `scripts/coupang_goods_info.py:40-50` - `scripts/coupang_site_list.py:58-65` - `scripts/coupang_search_common.py:108-111` - `scripts/geekbi_auth.py:578-580` - `scripts/geekbi_auth.py:698-721` **Vulnerability Type**: Unvalidated network destination and insecure transport configuration **Risk Level**: Medium ### Vulnerable Code ```python # scripts/coupang_goods_search.py:64-73 parser = argparse.ArgumentParser(description="查询 Coupang 商品并输出 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 ) ``` ```python # scripts/coupang_search_common.py:108-111 def build_url(base_url, endpoint, params): url = f"{base_url.rstrip('/')}{endpoint}" query = urlencode(params) return f"{url}?{query}" if query else url ``` ```python # scripts/geekbi_auth.py:578-580 endpoint = f"{base_url.rstrip('/')}{TOKEN_ENDPOINT}" try: response = _post_json(endpoint, {"deviceCode": pending["deviceCode"]}, timeout) ``` ```python # scripts/geekbi_auth.py:698-721 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: r ...[truncated 3401 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` from production-facing CLIs and use the fixed GeekBI HTTPS origin. 2. If alternate origins are required for testing, place the option behind an explicit development-mode flag that is disabled by default. 3. Parse destinations with `urllib.parse.urlsplit` and enforce all of the following: - Scheme must be `https`. - Host must match an explicit allowlist, preferably only `openapi.geekbi.com`. - User information, query strings, and fragments must not be present in the base URL. - Ports must be restricted to approved HTTPS ports. - Loopback, private, link-local, multicast, and unspecified IP addresses must be rejected. 4. Resolve hostnames safely and account for DNS rebinding before connecting to non-fixed destinations. 5. Validate every server-provided `jumpUrl` against a separate allowlist of approved HTTPS authentication origins before returning it to the user. 6. Do not permit redirects to a different origin during authenticated requests. Revalidate the destination after every redirect or disable automatic redirects. 7. Use the standard `Authorization: Bearer ...` header unless the API contract explicitly requires the custom `token` header. 8. Add tests covering HTTP URLs, embedded credentials, alternate domains, localhost, private IP ranges, IPv6 loopback, malformed URLs, malicious login URLs, and cross-origin redirects. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/geekbi_auth.py:70
Finding
Bearer Tokens Are Unnecessarily Mirrored into Skill and Workspace Directories<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/geekbi_auth.py:53-83` - `scripts/geekbi_auth.py:383-397` - `scripts/geekbi_auth.py:631-652` **Vulnerability Type**: Excessive credential storage and expanded secret exposure **Risk Level**: Low ### Vulnerable Code ```python # scripts/geekbi_auth.py:53-83 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) ``` ```python # scripts/geekbi_auth.py:383-397 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 # scripts/geekbi_auth.py:631-652 token_data = response["data"] access_token = token_data.get("accessToken") if not isinstance(access_token, str) or not access_token: raise ValueError("登录令牌响应缺少 accessToken") expires_in = int( ...[truncated 3323 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store authentication state in exactly one user-specific location rather than mirroring it into the Skill and working directories. 2. Prefer an operating-system credential manager or keychain for the bearer token. Keep only non-sensitive metadata in a JSON state file. 3. If file storage is unavoidable: - Use only the user configuration directory. - Require restrictive ownership and permissions before writing the token. - Fail closed if permissions cannot be enforced. - Avoid storing tokens on shared or network-mounted filesystems. 4. Correct the apparent legacy directory name `temu-research-skill` so Coupang authentication state is not unexpectedly mixed with another Skill namespace. 5. Make cleanup report every path that could not be removed instead of silently suppressing deletion errors. 6. During migration, securely remove existing copies from the Skill and workspace directories after moving the valid state to the canonical store. 7. Document token lifetime, scope, storage location, logout behavior, and revocation procedures. 8. Add tests confirming that authentication never creates `.geekbi/agent-auth.json` in the current workspace or installed Skill directory. ]]>
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
86% confidence
Finding
The skill invokes local scripts and reads reference files, implying file_read, shell, and likely network access, but it declares no permissions or capability constraints. This is dangerous because undeclared powerful capabilities reduce reviewability and can allow unexpected external requests or command execution paths beyond what users or the platform expect.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The auth state is stored under a different skill namespace ('temu-research-skill'), which can cause cross-skill state confusion and unintended credential sharing if another skill uses the same path. In this authentication wrapper, that means a Coupang/GeekBI session could be read, overwritten, or cleared by unrelated code, weakening isolation between skills and potentially exposing bearer tokens or login state.

Static analysis

No suspicious patterns detected.