Back to skill

Security audit

极鲸云Coupang数据分析与市场调研

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real Coupang research tool, but its authentication handling stores bearer tokens too broadly and can send authenticated requests to user-supplied API origins.

Review before installing. Use it only if you trust GeekBI and are comfortable authenticating to its API. Avoid custom --base-url values unless you are deliberately using a trusted HTTPS GeekBI endpoint, verify any login link before opening it, and do not run the skill from shared repositories or synced folders unless the token-mirroring behavior is fixed or you clear auth state afterward.

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:698
Finding
Unrestricted API Origin Can Receive Authentication Material<![CDATA[ ## Vulnerability Details **File Location**: `scripts/coupang_goods_search.py:65-72`, `scripts/coupang_search_common.py:108-111`, and `scripts/geekbi_auth.py:564-578, 698-721` **Vulnerability Type**: Missing destination and transport validation for authenticated requests **Risk Level**: Medium ### Vulnerable Code ```python # scripts/coupang_goods_search.py:65-72 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:564-578 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}" ``` ```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"] = authorizatio ...[truncated 3148 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` from production-facing commands if endpoint customization is not required. 2. Otherwise, parse the URL with `urllib.parse.urlsplit()` and require: - The `https` scheme. - An exact approved hostname such as `openapi.geekbi.com`. - An approved port. - No embedded username or password. - No fragments or malformed authority components. 3. Before attaching a bearer value, independently verify that `url` and `base_url` resolve to the same approved origin. 4. Reject redirects to different origins for authenticated requests, or implement explicit same-origin redirect validation. 5. Validate server-provided login links against a separate allowlist of HTTPS authentication hosts before displaying them. 6. If custom development endpoints are necessary, gate them behind an explicit unsafe-development option and use isolated test credentials that cannot access production data. 7. Add tests proving that HTTP URLs, deceptive hostnames, embedded credentials, nonstandard ports, and unapproved origins are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geekbi_auth.py:65
Finding
Plaintext Bearer Tokens Are Mirrored into Skill and Working Directories<![CDATA[ ## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:65-101, 369-383, 637-648` **Vulnerability Type**: Excessive and insecure credential persistence **Risk Level**: Medium ### Vulnerable Code ```python # scripts/geekbi_auth.py:65-79 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) ``` ```python # scripts/geekbi_auth.py:84-101 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:369-383 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:637-648 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 i ...[truncated 3042 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store authentication state only in the platform-specific user configuration directory. 2. Prefer an operating-system credential manager, such as Keychain, Credential Manager, or Secret Service, for bearer-token storage. 3. Remove automatic writes to the Skill directory and current working directory. 4. If fallback storage is operationally unavoidable: - Require explicit user opt-in. - Display the exact destination before writing. - Never mirror the credential to multiple stores. - Refuse shared or overly permissive directories. 5. On Windows and other non-POSIX platforms, apply platform-native access-control lists so only the current user can read the credential. 6. Update `clear_auth_state()` and migration logic to remove all legacy copies from previous storage locations. 7. Document the credential location, expiry behavior, cleanup procedure, and risks of copying workspaces. 8. Add tests confirming that successful authentication creates only one protected credential record and never writes beneath the current project directory. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to read local reference files and run multiple scripts that imply file access, shell execution, and network-backed data retrieval, yet no explicit permissions are declared. This creates a governance gap: reviewers and runtime policy systems cannot clearly constrain or audit what the skill is allowed to access, increasing the chance of overbroad execution or unintended data exposure.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The auth state path is written under a different skill namespace ("temu-research-skill") than the declared Coupang skill. This can cause credential/state confusion across skills, leading to unintended token reuse, cross-skill access to login state, or accidental exposure/overwrite if another skill uses the same directory.

Vague Triggers

Low
Confidence
89% confidence
Finding
The skill metadata is broadly scoped and does not clearly constrain when the skill should activate, which can cause over-invocation for loosely related Coupang or market-research requests. In an agent system, ambiguous activation boundaries increase the chance of the wrong tool being selected, potentially exposing external data access or producing unintended business analysis beyond the user's actual request.

Static analysis

No suspicious patterns detected.