Back to skill

Security audit

极鲸云速卖通类目搜索

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its AliExpress research purpose, but its login handling is too broad and could expose authentication tokens or send users to untrusted login links.

Install only if you trust GeekBI and can control how the scripts are invoked. Do not pass custom --base-url values, be cautious with any login link the agent shows, and check for .geekbi/agent-auth.json files in project or skill directories after use. A safer version would pin authenticated requests to known HTTPS GeekBI origins and store tokens in one dedicated user credential location.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/aliexpress_goods_search.py:54
Finding
Caller-Controlled Base URL Permits Plaintext Authentication Traffic and Unrestricted Credential Destinations## Vulnerability Details **File Location**: `scripts/aliexpress_goods_search.py:54-64` and equivalent `--base-url` handling in the category and site scripts; request behavior is implemented in `scripts/geekbi_auth.py:698-721` **Vulnerability Type**: Unvalidated authentication endpoint and insecure transport **Risk Level**: High ### Complete Code Snippet ```python def main(): parser = argparse.ArgumentParser(description="Query AliExpress goods and output JSON") parser.add_argument("--base-url", default=DEFAULT_BASE_URL) parser.add_argument("--param", action="append", default=[], help="Query parameter") 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 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) ``` ### Technical Analysis Every business script exposes `--base-url` directly to the caller. The value is concatenated with API paths and passed into the authentication subsystem without scheme, hostname, port, or origin validation. Authentication state is keyed by that caller-controlled value. Once an authentication challenge has been c ...[truncated 2163 chars]
Remediation
## Remediation Suggestions - Remove `--base-url` from production-facing scripts unless alternate servers are essential. - If configurability is required, parse the URL with `urllib.parse.urlsplit` and require: - `scheme == "https"`; - an exact hostname allowlist; - approved ports only; - no embedded username or password; - no fragments or unexpected path prefixes. - Bind credentials to a normalized origin tuple rather than an unvalidated string. - Refuse to attach authentication headers when the request URL and authenticated origin differ. - Disable or strictly validate redirects for authenticated requests; never forward authentication headers across origins or to a downgraded HTTP destination. - Use a separate explicit development option for localhost testing, with authentication disabled or isolated credentials. - Add tests covering HTTP rejection, lookalike domains, user-info URLs, cross-origin redirects, alternate ports, and hostname normalization.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geekbi_auth.py:68
Finding
Bearer Tokens and Device Login State Are Replicated in Plaintext Across Multiple Filesystem Locations## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:68-105`, `scripts/geekbi_auth.py:365-388`, and `scripts/geekbi_auth.py:637-652` **Vulnerability Type**: Excessive credential persistence and plaintext secret storage **Risk Level**: Medium ### Complete Code Snippet ```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 "Authentication state directory unavailable" 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_serve ...[truncated 3101 chars]
Remediation
## Remediation Suggestions - Store authentication state in exactly one dedicated per-user configuration location. - Remove the Skill-directory and current-working-directory stores. - Correct the unrelated `temu-research-skill` directory name and implement a deliberate migration that deletes obsolete copies after successful import. - Prefer an operating-system credential facility such as Keychain, Credential Manager, Secret Service, or a maintained keyring abstraction for the bearer token. - If file storage remains necessary: - store only minimal metadata in JSON; - encrypt or separately protect the bearer token; - fail closed if restrictive permissions cannot be enforced; - verify ownership and reject unsafe links or unexpected file types; - avoid writing secrets to synchronized or repository-controlled paths. - On logout, remove all legacy copies and invalidate the server-side token where supported. - Document the storage location, token scope, expiry, and cleanup behavior. - Add tests ensuring no credential file is created beneath the current working directory or installed Skill tree.

other

Warning
Location
scripts/geekbi_auth.py:503
Finding
Unvalidated Server-Supplied URLs Are Presented to Users as Authentication Links## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:503-517` and `references/查询暂停与恢复流程.md:3-8` **Vulnerability Type**: Server-driven phishing and unsafe URL presentation **Risk Level**: Medium ### Complete Code Snippet ```python def _raise_action_if_needed(payload): data = payload.get("data", {}) if isinstance(payload, dict) else {} jump_url = data.get("jumpUrl") if isinstance(data, dict) else None if not isinstance(jump_url, str) or not jump_url: return raise ActionRequired( response_message(payload, "Please complete the page action before continuing"), jump_url, action=data.get("error") or "ACTION_REQUIRED", expires_in=int(data.get("expiresIn", 0)), ) ``` The workflow documentation instructs the Agent to use the server message verbatim and present `jumpUrl` as a clickable Markdown link without generating or rewriting it. ### Technical Analysis Any response containing a non-empty `data.jumpUrl` is promoted into an `ActionRequired` object. There is no validation of the URL scheme, hostname, port, user-information component, or relationship to the trusted API origin. The accompanying workflow explicitly directs the Agent to expose this server-controlled value as a clickable link and to reproduce the server-controlled message verbatim. This creates a trusted user-interface channel for phishing. The risk is amplified by the caller-controlled `--base-url` issue, because an arbitrary endpoint can intentionally return a deceptive message and login URL. Even with the default endpoint, compromise or misconfiguration of the service could turn the same mechanism into a phishing vector. Displaying a legitimate authentication URL is necessary for the device-login workflow, but accepting any URL is broader than necessary. A secure implementation should constrain authentication links to documented HTTPS origins and present the destination clearly. ...[truncated 1132 chars]
Remediation
## Remediation Suggestions - Parse `jumpUrl` and require HTTPS. - Allow only exact, documented authentication hostnames and approved ports. - Reject embedded credentials, IP-literal destinations, fragments, and confusing Unicode or lookalike hostnames. - If cross-domain authentication is required, maintain a small explicit allowlist rather than trusting arbitrary response values. - Present the normalized destination hostname visibly and ask for confirmation before opening it. - Do not reproduce arbitrary server text verbatim in a privileged Agent voice; wrap it as untrusted service-provided text. - Bind the login challenge to the expected API origin and verify that the token exchange returns to that same origin. - Add tests for `javascript:`, `data:`, plaintext HTTP, user-information URLs, lookalike domains, and URL parser edge cases.
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
88% confidence
Finding
The skill instructs the agent to invoke local scripts and read reference files, which implies shell execution, file reads, and likely network access, but no explicit permissions are declared. This creates a capability/permission mismatch that can lead to over-privileged or opaque execution, making it harder to review, sandbox, and constrain what the skill is allowed to do.

Vague Triggers

Medium
Confidence
76% confidence
Finding
The activation text is broad enough to trigger on general discussions of AliExpress categories, category IDs, market research, or product selection, without strong exclusion conditions. Over-broad invocation can cause the skill to run in unintended contexts, leading to unnecessary external queries, misleading reliance on sampled data, or expanded exposure of the agent's tool capabilities.

Static analysis

No suspicious patterns detected.