Back to skill

Security audit

Bitget Wallet

Security checks for vulnerabilities and agentic risk

Overview

The skill is a Bitget Wallet API helper, but it includes under-scoped wallet signing and transaction submission paths that can move funds and expose private keys.

Review this carefully before installing. Treat it as a trading and wallet-signing skill, not just a market-data tool. Do not pass valuable wallet private keys on the command line, do not use the self-update flow from a mutable branch without separate review, and only use signing or order submission with a dedicated low-value wallet after independently checking the transaction details.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/order_sign.py:31
Finding
Blind Signing of Server-Controlled Hashes and Transactions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/order_sign.py:31-49`, `scripts/order_sign.py:71-101`; related trust instructions in `SKILL.md:362-400` and `SKILL.md:499-508` **Vulnerability Type**: Signing unverified API-controlled payloads **Risk Level**: Critical ### Vulnerable Code ```python def sign_order_signatures(order_data: dict, private_key: str) -> list[str]: acct = Account.from_key(private_key) signed_list = [] sigs = order_data.get("signatures", []) if not sigs: raise ValueError("No signatures in order data. Is this a 'txs' mode order?") for item in sigs: api_hash = item.get("hash") if not api_hash: raise ValueError(f"Missing 'hash' field in signature item: {item}") hash_bytes = bytes.fromhex(api_hash[2:]) signed = acct.unsafe_sign_hash(hash_bytes) sig_hex = "0x" + signed.signature.hex() signed_list.append(sig_hex) return signed_list ``` The normal transaction mode similarly trusts every transaction field supplied by the API: ```python for tx_item in txs: tx_data = tx_item["data"] cid = chain_id or int(tx_item.get("chainId", 1)) tx_dict = { "to": tx_data["to"], "data": tx_data["calldata"], "gas": int(tx_data["gasLimit"]), "nonce": int(tx_data["nonce"]), "chainId": cid, } if tx_data.get("supportEIP1559") or tx_data.get("maxFeePerGas"): tx_dict["maxFeePerGas"] = int(tx_data["maxFeePerGas"]) tx_dict["maxPriorityFeePerGas"] = int(tx_data["maxPriorityFeePerGas"]) tx_dict["type"] = 2 else: tx_dict["gasPrice"] = int(tx_data["gasPrice"]) value = tx_data.get("value", "0") if isinstance(value, str) and "." in value: tx_dict["value"] = int(float(value) * 1e18) else: tx_dict["value"] = int(value) signed_tx = acct.sign_transaction(tx_dict) signed_list.append("0x" + signed_tx.raw_transaction.hex()) ``` ### Technical ...[truncated 2464 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Independently reconstruct every EIP-712 and EIP-7702 digest and compare it with the API-provided hash before signing. 2. Reject signatures when the structured message cannot be deterministically verified. 3. Decode calldata and validate: - Function selectors; - Token contracts; - Approval spenders and allowance amounts; - Swap routers; - Input and minimum output amounts; - Recipients; - Deadlines; - Native-token values. 4. Verify the sender, chain ID, nonce, verifying contract, and EIP-7702 delegation target against explicit allowlists. 5. Bind the signed payload to the exact order details previously shown to and approved by the user. 6. Require confirmation through a wallet-native interface that displays decoded transaction effects. 7. Treat unknown fields, unknown contracts, hash mismatches, and malformed hashes as fatal errors. 8. Add tests using malicious API responses to ensure altered recipients, values, calldata, chain IDs, delegation targets, and approval amounts are rejected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/order_sign.py:9
Finding
Wallet Private Key Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/order_sign.py:9-12`, `scripts/order_sign.py:104-112`; documented usage in `SKILL.md:400` **Vulnerability Type**: Plaintext secret exposure through process arguments **Risk Level**: High ### Vulnerable Code ```python Usage: python3 scripts/order_sign.py --order-json '<json>' --private-key <hex> # Or pipe order-create output: python3 scripts/bitget_api.py order-create ... | python3 scripts/order_sign.py --private-key <hex> ``` ```python def main(): parser = argparse.ArgumentParser(description="Sign order-create response") parser.add_argument("--order-json", help="Order-create response JSON string") parser.add_argument("--private-key", required=True, help="Hex private key") args = parser.parse_args() ``` ### Technical Analysis The signing helper requires the complete wallet private key to be supplied as a command-line argument. Command-line arguments are not a suitable secret transport mechanism because they may be recorded or exposed through: - Shell history; - Process inspection utilities and `/proc`; - Agent command transcripts; - Terminal logging; - CI/CD logs; - Monitoring and telemetry; - Error reports or debugging output. This contradicts the Skill’s stated key-management principle of minimal privilege and no persistence. Deleting the in-process Python variable later would not remove copies retained by the shell, operating system, agent runtime, or logging infrastructure. ### Attack Path 1. A user or agent follows the documented command and includes the wallet private key after `--private-key`. 2. The shell, agent runtime, or process table records the command-line argument. 3. A local process, administrator, monitoring service, transcript reader, or later log consumer accesses the recorded argument. 4. The attacker extracts the private key. 5. The attacker imports the key into another wallet and signs arbitrary transactions independently of the Skill’s confir ...[truncated 507 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--private-key` command-line option. 2. Prefer a hardware wallet, wallet RPC, OS keychain, isolated signing service, or secret-manager signing operation in which raw key material never enters the agent process. 3. If local secret input is unavoidable, use an interactive no-echo prompt or a protected inherited file descriptor rather than argv, environment variables, or shell substitution. 4. Ensure agent command logging and transcript capture cannot record secret-bearing inputs. 5. Run the signer in an isolated process with minimal filesystem and network privileges. 6. Zeroize mutable secret buffers where technically possible, while recognizing that Python strings cannot be reliably zeroized. 7. Rotate any private key that has previously been passed through the documented command-line interface. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:25
Finding
Mutable Remote Self-Update Replaces Audited Skill Code and Instructions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:25-54` **Vulnerability Type**: Unpinned remote payload retrieval and activation **Risk Level**: High ### Vulnerable Instructions ```text Daily first-use version check: On the first use of the week (at most once every 7 days), compare the installed version (from frontmatter) against the latest version available from the repository: 1. Check the installed version from frontmatter above 2. Fetch the latest CHANGELOG.md from https://raw.githubusercontent.com/bitget-wallet-ai-lab/bitget-wallet-skill/main/CHANGELOG.md 3. Compare the latest version in CHANGELOG with the installed version ``` ```text If the user confirms upgrade: Re-install the skill from the main branch of the repository at https://github.com/bitget-wallet-ai-lab/bitget-wallet-skill. Replace all local skill files with the latest versions, then re-read SKILL.md to load the updated Domain Knowledge. ``` ### Technical Analysis The Skill instructs the agent to retrieve metadata and replacement files from the mutable `main` branch. It then directs the agent to replace all local files and immediately re-read the new `SKILL.md`, making the remotely hosted content part of the active instruction and code-execution path. User confirmation provides an interaction checkpoint, but it does not establish artifact integrity or provenance. There is no requirement to pin a commit, verify a signed release, compare cryptographic hashes against trusted metadata, or obtain a security review before activation. The post-update diff instruction occurs after local files have already been replaced. Therefore, it does not prevent malicious instructions or scripts from becoming active. ### Attack Path 1. An attacker compromises the upstream repository, maintainer account, release process, or mutable branch. 2. The attacker modifies `SKILL.md`, `scripts/bitget_api.py`, `scripts/order_sign.py`, or another newly added file. 3. The periodic version check retri ...[truncated 1036 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Update only from immutable, reviewed commit hashes or signed release tags. 2. Verify release signatures and cryptographic checksums against metadata obtained through an independently trusted channel. 3. Download updates into a staging directory rather than replacing active files. 4. Audit the complete diff, including documentation, scripts, dependencies, and newly added files, before activation. 5. Require explicit approval after the audit, not before it. 6. Never immediately re-read or execute changed Skill instructions. 7. Preserve the previous version and support atomic rollback. 8. Restrict the update process so it cannot modify files outside the Skill directory. 9. Remove automated periodic remote checks if the environment cannot provide secure release verification. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
SKILL.md:797
Finding
Secret Retrieval Workflow Executes an Unverified Relative-Path Helper<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:797-806` **Vulnerability Type**: Local tool spoofing in a sensitive key-management workflow **Risk Level**: High ### Vulnerable Instructions ```python # Fetch from 1Password, use, discard import subprocess key = subprocess.run( ["python3.13", "scripts/op_sdk.py", "get", "Agent Wallet", "--field", "evm_key", "--reveal"], capture_output=True, text=True ).stdout.strip() # ... use key for signing ... del key # explicit cleanup ``` ### Technical Analysis The documented secret-retrieval pattern invokes `scripts/op_sdk.py` through a relative path. That file is not present in the audited project structure. The workflow therefore assumes the existence and trustworthiness of a helper whose implementation, origin, permissions, and integrity are not established by this package. If a file is later placed at that path—whether manually, through an update, or by another workspace component—the agent may execute it as part of a highly trusted wallet-key workflow. The example also fails to use `check=True`, verify the helper’s identity, validate file ownership and permissions, or confirm that the returned output is a correctly formatted key. Although the example does not send the key to a network endpoint itself, it places execution of an unverified local program directly in the secret-access path. ### Attack Path 1. An attacker gains the ability to create or replace `scripts/op_sdk.py` in the workspace, or distributes it through a compromised update. 2. The agent follows the documented 1Password retrieval pattern. 3. Python executes the attacker-controlled helper under the agent user’s privileges. 4. The helper performs arbitrary local or network operations while masquerading as the expected secret-retrieval tool. 5. It may return attacker-selected output, alter signing behavior, inspect accessible files, or interact with available credential services. 6. The agent subsequently treats the helper’s o ...[truncated 645 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the example until the referenced helper is included and independently audited. 2. Prefer the official 1Password CLI or SDK installed from a verified source. 3. Invoke security-sensitive tools through an absolute path and verify their expected version, owner, permissions, and cryptographic digest. 4. Use `subprocess.run(..., check=True)` and reject empty, malformed, or unexpected output. 5. Prevent writable workspace directories from supplying trusted executables. 6. Keep signing inside the secret manager or isolated signing service so the raw private key is never returned to the agent. 7. Apply least-privilege credential policies so the signer can access only one designated key and cannot enumerate unrelated vault items. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:159
Finding
Unpinned and Incompletely Declared Python Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `README.md:159-163`, `README.md:267`, `COMPATIBILITY.md:107-111`; undeclared import in `scripts/order_sign.py:20` **Vulnerability Type**: Unsafe and non-reproducible dependency installation **Risk Level**: Medium ### Vulnerable Instructions and Code ```text ### Prerequisites 1. Python 3.11+ 2. requests library (pip install requests) 3. That's it — public demo API credentials are built in. ``` ```text Dependencies: requests only (stdlib: hmac, hashlib, json, base64) ``` However, the signing helper imports an additional third-party package: ```python from eth_account import Account ``` The compatibility guide also records unconstrained installation: ```text 3. Ran `pip install requests` ``` ### Technical Analysis The project contains no pinned dependency manifest or hash-verified lockfile. Installing `requests` without a version constraint allows the resolved code to change between installations. The project also claims that `requests` is the only dependency, while `scripts/order_sign.py` requires `eth-account`. Users attempting to run the signer must discover and install this undeclared package separately, commonly through another unconstrained `pip install` operation. This creates a supply-chain and compatibility risk because dependency versions and transitive packages are not reproducible or reviewed. In a wallet-signing context, dependency integrity is particularly important: compromised or behaviorally incompatible signing libraries can affect private-key handling and transaction generation. ### Attack Path 1. A user follows the documentation and installs packages without pinned versions or hashes. 2. Package resolution selects whatever versions and transitive dependencies are current at installation time. 3. A compromised package release, compromised package index path, or incompatible future version is installed. 4. The package executes during installation, import, HTTP processing, or walle ...[truncated 708 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a dependency manifest that explicitly includes both `requests` and `eth-account`. 2. Pin exact direct and transitive versions using a lockfile. 3. Include package hashes and install with hash enforcement. 4. Use a dedicated virtual environment with no unrelated packages. 5. Run dependency vulnerability and provenance checks in CI. 6. Document the tested Python and library versions. 7. Review dependency updates before changing the lockfile, especially updates affecting cryptography, transaction serialization, or HTTP/TLS behavior. 8. Correct the documentation so it no longer claims that `requests` is the only dependency. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (24)

Tainted flow: 'headers' from os.environ.get (line 65, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
headers["Partner-Code"] = os.environ.get("BGW_PARTNER_CODE", DEFAULT_PARTNER_CODE)

    try:
        resp = requests.post(url, data=body_str if body_str else None, headers=headers, timeout=30)
        if resp.status_code != 200:
            return {"error": f"HTTP {resp.status_code}", "message": resp.text[:500]}
        return resp.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior includes private-key handling and direct signing of API-provided hashes via unsafe_sign_hash, which is materially more sensitive than the declared token-info and quote functionality. Hidden signing capability is especially dangerous because it can authorize asset transfers or approvals under the guise of a data-retrieval skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior includes private-key handling and direct signing of API-provided hashes via unsafe_sign_hash, which is materially more sensitive than the declared token-info and quote functionality. Hidden signing capability is especially dangerous because it can authorize asset transfers or approvals under the guise of a data-retrieval skill.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill is framed as an API client for market data and quotes, yet it operationally supports trade execution by creating orders, preparing calldata, signing, and broadcasting transactions. This is a scope deception issue: reviewers or users may invoke it expecting passive information access while it can actively move funds.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
8. Token safety status
9. EIP-712 verification (domain, msgSender, calls summary)

**Gas mode display rules:**
- Gasless with 7702 bound → "Gasless ✅ (EIP-7702 已绑定)"
- Gasless first time → "Gasless ✅ (EIP-7702 首次绑定, 2 signatures)"
- User override → "User Gas (native token)"
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The documentation instructs the agent to retrieve a private key from local secrets tooling and use it for transaction and hash signing. Embedding secret-retrieval and signing workflows inside a broadly described API skill greatly increases the blast radius: compromise of the skill or upstream API responses could lead to direct wallet authorization and loss of assets.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The skill metadata frames the capability as market data, token info, quotes, and security checks, but the implementation also supports creating swap orders, submitting signed transactions, and broadcasting them to a third-party API. That hidden expansion from informational queries into transaction execution materially increases risk because an agent or user may invoke the skill without understanding it can facilitate real asset movement.

Missing User Warnings

High
Confidence
97% confidence
Finding
The swap-send command broadcasts raw signed transactions to an external endpoint and lacks any explicit confirmation or strong warning despite directly enabling on-chain execution. In the context of a wallet-integrated crypto skill, this is especially dangerous because signed raw transactions are effectively authorization artifacts; once relayed, funds can move irreversibly.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
This file introduces transaction and hash-signing behavior that exceeds the skill's stated purpose of market data, token info, quotes, and security checks. In practice, this enables the skill to turn API-supplied payloads into user-authorized signatures, which can be abused to approve malicious swaps, permits, or arbitrary blockchain actions if the upstream response is tampered with or overly trusted.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script accepts a raw private key and uses it to sign either arbitrary hashes or full transactions derived from external input. Handling raw keys inside a market-data skill is highly dangerous because compromise of the skill, logs, shell history, pipelines, or upstream API responses can directly lead to unauthorized blockchain transactions and irreversible fund loss.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares no explicit tool scope or permission boundaries even though its content clearly requires network access and environment/secret access. In a skill that can fetch remote content, use API credentials, and participate in trading workflows, missing scope declarations increase the risk of overbroad execution and make review, sandboxing, and policy enforcement harder.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill instructs the agent to fetch remote files from GitHub and replace local skill files as part of an upgrade flow. This creates a remote self-modification path that can bypass normal review controls and introduces supply-chain risk if the repository, branch, or transport is compromised.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### Pre-Trade Workflow

Before executing any swap, the agent should silently run risk checks and then present a **single confirmation summary** to the user. Do not prompt the user at every step.

**Behind the scenes (agent runs automatically):**
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The markdown includes a prescribed status message of "等待确认..." for user output, which forces a specific language in at least one user-facing flow. The file does not state that responses should follow the user's preferred language or provide an opt-in for Chinese output, so this conflicts with the locale-choice policy.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The instruction says the user must explicitly say "yes" / "confirm" / "执行", embedding a specific non-default language token into the confirmation policy. Because no language selection or multilingual rationale is provided, this is a natural-language locale policy issue.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Why this order matters:**
- order-create before present: user sees real order data, not just estimates
- order-status for toAmount: more accurate than quote (accounts for actual routing)
- present before sign: user controls their funds, agent doesn't auto-execute
- **Skipping the confirmation step is a violation of the agent's operating rules**

**Completion message (same-chain):**
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
#### Gas Mode: Default to Gasless

**Always default to gasless** — pass `--feature no_gas` to `order-create` on every trade. Do not check `features` field first, do not ask the user to choose.

**How to detect gasless success vs fallback:**
- Response has `signatures` array (non-empty) → gasless mode active ✅
Confidence
80% confidence
Finding
The instruction to always default to gasless and not ask the user to choose preselects a financially and trust-significant execution mode. Even if later confirmation is required, auto-opting into a relayer-mediated signing flow changes trust assumptions and fee behavior without obtaining specific informed consent for that mode.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The example output hard-codes Chinese text ("gas 从输入金额扣除,小额交易 gas 占比较高") in a confirmation summary the user is expected to see. Since the skill does not frame this as region-specific or user-selected localization, it imposes a specific language/locale.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This line presents another required-looking user-facing warning in Chinese within the confirmation flow. Without any instruction to localize based on user preference, it effectively forces a specific language in normal operation.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The display rules explicitly define Chinese phrases like "已绑定" and "首次绑定" for user-visible gas mode labels. This is a policy concern because it mandates a locale-specific output style absent user opt-in or a documented regional scope.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### EVM Token Approval (Critical)

On EVM chains (Ethereum, BNB Chain, Base, Arbitrum, Optimism), tokens require an **approve** transaction before the router contract can spend them. **Without approval, the swap transaction will fail on-chain and still consume gas fees.**

- Before calling `swap-calldata`, check if the token has sufficient allowance for the BGW router (`0xBc1D9760bd6ca468CA9fB5Ff2CFbEAC35d86c973`).
- If allowance is 0 or less than the swap amount, an approve transaction must be sent first.
Confidence
88% confidence
Finding
The skill directs the agent to check allowance and send an approval transaction when needed, which is an asset-authorizing action. Although approval is operationally necessary for ERC-20 swaps, it is still a sensitive blockchain permission change and should not be automated implicitly because approvals can enable later token spending by a router contract.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The order submission path sends signed transaction blobs to an external API endpoint with only a generic command description and no explicit warning that the data authorizes on-chain actions. Even if the transactions are already signed, forwarding them to a remote service can trigger execution, leak sensitive transaction intent, and reduce the user's control over when and where the transaction is submitted.

Intent-Code Divergence

Medium
Confidence
88% confidence
Finding
The docstring frames the helper as only signing API-provided hashes without recomputing EIP-712 data, but the implementation also signs full raw transactions. That mismatch is security-relevant because it can mislead reviewers or users into underestimating the authority granted to the script, reducing scrutiny around a capability that can directly transfer assets or set approvals.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script takes the private key as a command-line argument, which commonly exposes secrets through shell history, process listings, CI logs, and pipeline telemetry. Even if the signing logic were legitimate, this handling materially increases the chance of credential leakage and subsequent wallet compromise.

Static analysis

No suspicious patterns detected.