Back to skill

Security audit

极鲸云美客多店铺搜索

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do the advertised Mercado Libre shop research, but it needs review because its authentication code can be pointed at arbitrary API origins and stores login tokens in multiple local locations.

Review before installing. Use only the default GeekBI endpoint, do not pass user-supplied --base-url values, and be aware that login tokens may be stored in several local files. Prefer a version that pins the API origin to https://openapi.geekbi.com and stores credentials in one protected per-user location or an OS credential manager.

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
Authentication Data Can Be Sent to Untrusted or Insecure Origins## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:698-721`; exposed through `--base-url` in `scripts/mercadolibre_mall_search.py:49-57`, `scripts/mercadolibre_mall_info.py:27-34`, and `scripts/mercadolibre_site_list.py:61-67` **Vulnerability Type**: Unrestricted authentication endpoint and transport **Risk Level**: High ### Vulnerable Code ```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: ``` The calling scripts expose the destination without validation: ```python parser.add_argument("--base-url", default=DEFAULT_BASE_URL) ... payload = authenticated_json_request( build_url(args.base_url, ENDPOINT, params), args.base_url, args.timeout ) ``` ### Technical Analysis The scripts accept an arbitrary `--base-url` and use it for API requests, authentication challenge processing, device-code polling, and bearer-token delivery. The value is not restricted to HTTPS, the expected GeekBI hostname, the default port, or an approved origin. Although authentication state is keyed by the supplied base URL, an attacker-controlled origin can initiate its own authentication challenge, supply an arbitrary `jumpUrl`, receive device-code polling data, and receive any token stored for that origin. Plain HTTP also exposes these values and query data to network interception. In addition, `urlopen` follows HTTP redirects by default. The code does not ...[truncated 2050 chars]
Remediation
## Remediation Suggestions 1. Remove the production `--base-url` option and use the fixed `https://openapi.geekbi.com` origin. 2. If endpoint configurability is required for testing, gate it behind an explicit development-only mode and enforce an allowlist of exact schemes, hostnames, and ports. 3. Reject HTTP, embedded URL credentials, fragments, unexpected ports, IP-literal destinations, and malformed origins. 4. Validate every authentication `jumpUrl` against a separate allowlist of approved HTTPS login origins before presenting it to the user. 5. Disable automatic redirects for requests containing authentication data, or implement a redirect handler that only permits same-origin HTTPS redirects. 6. Verify the final response URL before processing its body. 7. Do not propagate the `token` header across redirects or origin changes. 8. Add tests covering HTTP endpoints, deceptive hostnames, user-info URL syntax, nonstandard ports, cross-origin redirects, and malicious `jumpUrl` responses.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geekbi_auth.py:69
Finding
Bearer Tokens Are Unnecessarily Replicated Across Multiple Local Stores## Vulnerability Details **File Location**: `scripts/geekbi_auth.py:69-83`, `scripts/geekbi_auth.py:368-379`, and `scripts/geekbi_auth.py:631-648` **Vulnerability Type**: Excessive plaintext credential storage and cross-Skill namespace collision **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) ``` The complete normalized state is 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) ``` The replicated state includes the bearer token: ```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) return True, True ` ...[truncated 2423 chars]
Remediation
## Remediation Suggestions 1. Store authentication state in only one per-user configuration location, or preferably in the operating system's credential manager. 2. Remove `_skill_state_path` and `_workspace_state_path` from the credential-store resolution process. 3. Correct the namespace from `temu-research-skill` to a unique Mercado Libre Skill identifier. 4. Store only non-sensitive metadata in JSON; place bearer tokens in Keychain, Credential Manager, Secret Service, or an equivalent secure facility. 5. Implement a migration that reads legacy locations once, moves valid state to the protected store, and securely removes old copies where feasible. 6. Ensure migration does not automatically trust conflicting state from an unrelated namespace. 7. Preserve restrictive permissions and fail closed if secure storage cannot be established. 8. Document token lifetime, revocation behavior, storage location, and a reliable command for clearing all legacy authentication state.
Vulnerability Patterns
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs the agent to invoke local scripts and consult local reference files, which implies shell execution, file reads, and likely outbound/network-backed data access, yet it declares no permissions. This creates a mismatch between apparent capabilities and stated security boundaries, reducing transparency and making it harder for the platform or reviewers to enforce least privilege and assess risk.

Static analysis

No suspicious patterns detected.