Back to skill

Security audit

Bitget Poolx Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill has a plausible monitoring purpose, but it ships under-scoped billing code with a hardcoded payment API key and an undocumented browser-scraping path that disables important safety controls.

Review before installing or running. Use only in a constrained environment with explicit network limits, avoid bitget-final.py unless it is removed or hardened, require the SkillPay key to be revoked and replaced with server-side scoped billing, and require clear per-charge consent plus disclosure of r.jina.ai and SkillPay data flows.

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
billing.py:8
Finding
Hardcoded SkillPay API Credential Exposed in Source Code## Vulnerability Details **File Location**: `billing.py:7-8`, with credential use at `billing.py:14`, `billing.py:30-35`, and `billing.py:59-64` **Vulnerability Type**: Hardcoded secret and reusable API credential **Risk Level**: High ### Vulnerable Code ```python BILLING_API_URL = "https://skillpay.me" BILLING_API_KEY = "sk_0c57911690182c45404f945f2908a9e2e32ed448055895ac02227856eaf226ad" SKILL_ID = "6a3b1843-5266-40c6-8f0c-408512bb6f43" ``` The credential is attached to multiple requests: ```python headers = {"X-API-Key": BILLING_API_KEY} ``` ```python headers = { "X-API-Key": BILLING_API_KEY, "Content-Type": "application/json" } ``` ### Technical Analysis A credential that appears to be a live SkillPay API key is embedded directly in the distributed Python source. Any party able to download, inspect, or execute the Skill can recover the key without authentication. The key is reused for balance queries, user charges, and payment-link creation. Although billing is part of the functionality declared in `SKILL.md`, distributing a reusable billing credential to every installation is not necessary and violates least-secret-exposure practices. The monitor should obtain a narrowly scoped credential at deployment or use a trusted server-side billing broker. Whether the exposed key permits access outside the configured Skill depends on SkillPay's server-side authorization. Client-side constants such as `SKILL_ID` do not provide a security boundary because an attacker can modify them. ### Attack Path 1. An attacker downloads or otherwise gains read access to the Skill package. 2. The attacker opens `billing.py` and extracts `BILLING_API_KEY`. 3. The attacker sends independent HTTPS requests to the documented SkillPay endpoints with the extracted key in the `X-API-Key` header. 4. The attacker attempts balance queries, payment-link generation, or charge operations for chosen user identifiers. 5. ...[truncated 707 chars]
Remediation
## Remediation Suggestions 1. Revoke and rotate the exposed API key immediately; removing it from a later revision does not invalidate copies already distributed. 2. Remove all credentials from source code and repository history. 3. Load deployment secrets from a managed secret store or a protected environment variable. 4. Prefer short-lived, narrowly scoped tokens instead of a reusable account-level key. 5. Restrict the credential server-side to the required Skill, endpoints, amount limits, and expected caller identity. 6. Require independent server-side authorization for each user and charge; never treat possession of the API key alone as authorization. 7. Add rate limits, transaction limits, replay protection, audit logging, and anomaly alerts to billing operations. 8. Add automated secret scanning to development and release pipelines.

T09 · Insecure Skill Coding Practices

Warning
Location
billing.py:14
Finding
User Identifiers Transmitted to a Third-Party Billing Service Without Documented Privacy Controls## Vulnerability Details **File Location**: `billing.py:14-16`, `billing.py:33-37`, and `billing.py:63-65` **Vulnerability Type**: External disclosure of caller-supplied identifiers **Risk Level**: Medium ### Vulnerable Code ```python def check_balance(user_id): """查询用户余额""" url = f"{BILLING_API_URL}/api/v1/billing/balance" headers = {"X-API-Key": BILLING_API_KEY} try: resp = requests.get(f"{url}?user_id={user_id}", headers=headers, timeout=10) ``` ```python data = { "user_id": user_id, "skill_id": SKILL_ID, "amount": amount } try: resp = requests.post(url, json=data, headers=headers, timeout=10) ``` ```python data = {"user_id": user_id, "amount": amount} try: resp = requests.post(url, json=data, headers=headers, timeout=10) ``` ### Technical Analysis The billing functions transmit arbitrary caller-provided `user_id` values to `https://skillpay.me`. The balance endpoint places the identifier in the URL query string, while charge and payment-link endpoints include it in JSON request bodies. Billing integration is disclosed in `SKILL.md`, so the network communication is not hidden and may be functionally necessary when a user explicitly uses paid features. However, the documentation does not identify what form of user identifier should be supplied, whether it must be pseudonymous, or how the third party stores and processes it. Query-string transmission creates additional exposure because URLs are commonly recorded in client histories, reverse-proxy logs, web-server access logs, monitoring systems, and analytics products. HTTPS protects the request in transit but does not prevent endpoint-side logging or retention. The main monitor does not import or invoke `billing.py`; therefore, collecting or transmitting a user identifier during ordinary monitoring is not required by the implementation reviewed. Billing should remain isolated and be i ...[truncated 1283 chars]
Remediation
## Remediation Suggestions 1. Document that billing sends an identifier, Skill ID, and transaction amount to SkillPay before the operation occurs. 2. Obtain explicit user consent before transmitting identity-linked billing data. 3. Accept only opaque, pseudonymous identifiers generated specifically for billing; reject emails, names, access tokens, and platform credentials. 4. Move the balance request from a query parameter to a request body where the API supports it, reducing accidental URL-log exposure. 5. Validate and length-limit `user_id` locally and enforce ownership authorization server-side. 6. Ensure SkillPay prevents one user from querying or charging another user's account based only on a caller-supplied identifier. 7. Define retention, deletion, access-control, and audit policies for billing records. 8. Keep billing opt-in and isolated from ordinary PoolX monitoring so no identifier is transmitted merely to retrieve public project information.

T09 · Insecure Skill Coding Practices

Error
Location
bitget-final.py:9
Finding
Remote Web Content Rendered with the Chromium Sandbox Disabled## Vulnerability Details **File Location**: `bitget-final.py:9-14` **Vulnerability Type**: Browser process isolation disabled **Risk Level**: High ### Vulnerable Code ```python browser = p.chromium.launch( headless=True, args=[ '--disable-blink-features=AutomationControlled', '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--no-first-run', '--no-zygote', '--disable-gpu', ] ) ``` The unsandboxed browser subsequently renders a remote page: ```python page.goto("https://www.bitget.com/events/poolx", timeout=45000) ``` ### Technical Analysis The alternate Playwright implementation explicitly starts Chromium with both `--no-sandbox` and `--disable-setuid-sandbox`. It then renders active content obtained from a remote website. A browser sandbox is a defense-in-depth boundary intended to constrain a compromised renderer process. Disabling it does not itself exploit the host, but it materially increases the potential impact of a browser or rendering-engine vulnerability triggered by remote content. This configuration exceeds the minimum privileges required for the declared Skill functionality. `SKILL.md` states that the primary implementation uses `r.jina.ai` and needs no Playwright browser. The separate `bitget-final.py` implementation is therefore an unnecessary, higher-risk execution path. Other flags and the injected `navigator.webdriver` override are intended to reduce automation detection. They do not compensate for the removed process-isolation boundary. ### Attack Path 1. A user executes `bitget-final.py`. 2. Playwright launches Chromium with its sandbox disabled. 3. Chromium loads and processes scripts, markup, media, and other content from the Bitget page and its dependencies. 4. If that content, a dependency, or a compromised upstream service triggers ...[truncated 934 chars]
Remediation
## Remediation Suggestions 1. Remove `bitget-final.py` if it is obsolete, since the documented implementation does not require Playwright. 2. If browser automation must remain, delete `--no-sandbox` and `--disable-setuid-sandbox`. 3. Run Chromium as a dedicated, unprivileged operating-system user with a minimal filesystem view. 4. Place browser execution in a hardened container or sandbox with a read-only root filesystem, dropped Linux capabilities, no host mounts, and strict seccomp/AppArmor policies. 5. Restrict outbound network access to the required domains and block access to loopback, private networks, and cloud metadata endpoints. 6. Keep Chromium and Playwright patched and pinned to reviewed versions. 7. Do not run the script as root. If the deployment environment requires disabling Chromium's sandbox, treat that as an unsupported configuration rather than silently lowering security. 8. Prefer fetching and parsing narrowly scoped public data over rendering a full remote web application.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill advertises Bitget PoolX monitoring via r.jina.ai and token launch detection, but the observed behavior reportedly does not use the claimed access method and does not actually detect token-specific launches. This is a security-relevant integrity issue because users may trust false capabilities, make decisions on inaccurate monitoring, or overlook the real network behavior of the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill advertises Bitget PoolX monitoring via r.jina.ai and token launch detection, but the observed behavior reportedly does not use the claimed access method and does not actually detect token-specific launches. This is a security-relevant integrity issue because users may trust false capabilities, make decisions on inaccurate monitoring, or overlook the real network behavior of the code.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The file embeds full billing and charging logic even though the declared skill purpose is only monitoring Bitget PoolX staking launches. This capability mismatch is dangerous because it introduces undisclosed monetization behavior, including charging users and transmitting billing identifiers to a third-party service unrelated to the stated monitoring function.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
A monitoring-only skill should not contain functionality to check balances, charge users, and generate payment links without a clear functional need. In context, this looks like unjustified billing logic that could be used to monetize or abuse users under the guise of a harmless market-monitoring tool.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill declares network-capable behavior but does not define any explicit tool scope such as permissions or allowed-tools. This weakens containment and reviewability, because consumers cannot easily tell what outbound access the skill requires, and an agent runtime may permit broader network use than intended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill routes requests through r.jina.ai, a third-party proxy, to retrieve Bitget content but does not clearly warn users about that data path. This is dangerous because user requests, metadata, and potentially sensitive operational context are exposed to an intermediary, and the proxy may alter content, log traffic, or create compliance and trust issues.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
Natural-language content in the module docstring and user-facing messages is exclusively in Chinese, with no opt-in or language-selection mechanism. This can violate language/locale policy when a skill imposes a specific language on users without documented justification.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The `charge_user` function can initiate a billing charge using a user identifier with no in-function confirmation, consent record, or visible warning. This creates a risk of unauthorized or surprise charges, especially because the skill's advertised purpose gives users no reason to expect direct billing behavior.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    
    try:
        resp = requests.post(url, json=data, headers=headers, timeout=10)
        result = resp.json()
        
        if result.get("success"):
Confidence
89% confidence
Finding
This line transmits user billing data (`user_id`, `skill_id`, `amount`) to an external service together with a hardcoded API key-backed billing action. External transmission is especially sensitive here because it directly supports charging behavior that is not aligned with the skill's stated monitoring purpose.

Tainted flow: 'data' from requests.get (line 18, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
}
    
    try:
        resp = requests.post(url, json=data, headers=headers, timeout=10)
        result = resp.json()
        
        if result.get("success"):
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'data' from requests.get (line 18, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
}
    
    try:
        resp = requests.post(url, json=data, headers=headers, timeout=10)
        result = resp.json()
        
        if result.get("success"):
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

External Transmission

Medium
Category
Data Exfiltration
Content
data = {"user_id": user_id, "amount": amount}
    
    try:
        resp = requests.post(url, json=data, headers=headers, timeout=10)
        result = resp.json()
        return result.get("payment_url", "")
    except Exception as e:
Confidence
84% confidence
Finding
This request sends `user_id` and payment amount to an external billing endpoint to generate a payment link. Although less severe than direct charging, it still shares billing-related user data with a third party in a context where users would not reasonably expect payment processing from a pool-monitoring skill.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill metadata claims it uses r.jina.ai to access content, but the implementation instead directly automates a browser against Bitget and includes logic to detect Cloudflare challenge pages. This mismatch is security-relevant because it conceals the real network behavior of the skill and indicates attempted access to a site through anti-bot controls, which increases the risk of policy evasion and misuse.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The code launches Chromium with multiple anti-detection flags, overrides navigator.webdriver, and explicitly checks whether Cloudflare has blocked the session. These stealth measures are not necessary for simple monitoring and strongly suggest deliberate evasion of bot detection, enabling unauthorized scraping or repeated automated access while masking automation.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script sends requests to r.jina.ai, a third-party relay explicitly described as a way to bypass Cloudflare, which exposes user IP, timing, headers, and target-interest metadata to an additional external service without disclosure or consent. In this skill context, the relay is not incidental but core to operation, which increases risk because users may believe they are only contacting Bitget while actually involving an untrusted intermediary.

Missing User Warnings

Low
Confidence
87% confidence
Finding
Generating a payment link sends user billing metadata to an external billing provider without any visible user-facing disclosure in this code path. While lower severity than direct charging, it still exposes user identifiers and starts a payment workflow unrelated to the stated monitoring function.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The file's human-facing docstrings and console messages are written exclusively in Chinese, which imposes a specific language on users without opt-in or explanation. Under the policy, language constraints should either provide user choice or be clearly justified as region-specific.

Static analysis

No suspicious patterns detected.