Back to skill

Security audit

Openclaw Fomo3d

Security checks for vulnerabilities and agentic risk

Overview

This blockchain game skill is not obviously malicious, but it needs review because it handles a wallet private key insecurely and grants very broad token approvals.

Install only if you are comfortable letting this skill sign real BNB Chain transactions. Prefer a fresh wallet funded only with the amount you are willing to lose, avoid running setup with a valuable private key, revoke token allowances after use, and review every buy, sell, bet, deposit, and approval before execution.

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
src/lib/config.ts:38
Finding
Wallet Private Key Is Collected Visibly and Stored in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `src/commands/setup.ts:16-33`; `src/lib/config.ts:38-41` **Vulnerability Type**: Plaintext sensitive-data storage and visible secret input **Risk Level**: High ### Vulnerable Code ```ts // src/commands/setup.ts:16-33 // 私钥 const currentKey = existing.privateKey ? `${existing.privateKey.slice(0, 6)}...${existing.privateKey.slice(-4)}` : "(not set)" log(`Current private key: ${currentKey}`) const keyInput = (await question(rl, "Private key (Enter to keep current): ")).trim() const privateKey = keyInput || existing.privateKey // 网络 log(`\nCurrent network: ${existing.network}`) const netInput = (await question(rl, "Network (testnet/mainnet, Enter to keep): ")).trim() const network = (netInput === "testnet" || netInput === "mainnet") ? netInput : existing.network // RPC URL log(`\nCurrent RPC URL: ${existing.rpcUrl ?? "(default)"}`) const rpcInput = (await question(rl, "Custom RPC URL (Enter for default): ")).trim() const rpcUrl = rpcInput || existing.rpcUrl const config = { privateKey, network, ...(rpcUrl ? { rpcUrl } : {}) } writeConfig(config) ``` ```ts // src/lib/config.ts:38-41 export function writeConfig(config: Partial<Config>): void { const existing = readConfigFile() ?? {} const merged = { ...existing, ...config } writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2) + "\n") } ``` ### Technical Analysis The setup command obtains the wallet private key through an ordinary `readline` question. Standard terminal input remains visible while the user types, allowing the secret to be exposed through shoulder surfing, terminal recording, screen sharing, or captured interactive-session output. The key is subsequently serialized into `config.json` as plaintext. `writeFileSync` is called without an explicit restrictive file mode such as `0o600`, so access depends on the process umask and any permissions already associated with the file. The audited project also did not include a `.gitignore` ent ...[truncated 1330 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not persist raw private keys in repository-local configuration files. 2. Prefer an operating-system credential store, encrypted keystore, hardware wallet, or external signing provider. 3. If file-based storage must remain supported: - Encrypt the key using a user-supplied passphrase and a modern authenticated encryption scheme. - Create the file with mode `0o600`. - Verify and reject unsafe permissions on existing files. - Use an atomic write strategy that preserves restrictive permissions. 4. Replace ordinary `readline` input with a secret-input mechanism that disables terminal echo. 5. Add `config.json` to `.gitignore` and packaging exclusions. 6. Store non-secret settings separately from wallet credentials. 7. Document that any previously exposed key must be retired; deleting the file alone does not invalidate a copied private key. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/lib/erc20.ts:23
Finding
ERC-20 Operations Grant Unlimited Token Allowances<![CDATA[ ## Vulnerability Details **File Location**: `src/lib/erc20.ts:23-38` **Vulnerability Type**: Excessive ERC-20 spending authorization **Risk Level**: High ### Vulnerable Code ```ts if (allowance >= requiredAmount) { log(`Allowance sufficient: ${allowance}`) return } log(`Approving token spend...`) const hash = await walletClient.writeContract({ address: tokenAddress, abi: ERC20_ABI, functionName: "approve", args: [spenderAddress, maxUint256], chain: walletClient.chain, }) log(`Approve tx: ${hash}`) await publicClient.waitForTransactionReceipt({ hash }) log("Approve confirmed") ``` ### Technical Analysis The helper receives a specific `requiredAmount`, but when the existing allowance is insufficient it authorizes `maxUint256` rather than the requested amount. This creates a practically unlimited and persistent spending authorization. The helper is used for game purchases, slot-machine operations, USDT purchases, and FOMO token sales. Consequently, the configured game and trading contracts may retain authority over all current and future balances of the approved token. An ERC-20 allowance is independent of the CLI process. Closing or uninstalling the skill does not revoke it. If an approved contract is malicious, compromised, incorrectly upgradeable, or contains an exploitable transfer path, it may use `transferFrom` to move substantially more than the amount associated with the transaction that caused the approval. ### Attack Path 1. A user invokes a command requiring an ERC-20 allowance. 2. The current allowance is lower than the requested transaction amount. 3. `ensureAllowance` submits an approval for `2^256 - 1`, not for `requiredAmount`. 4. The spender retains this authorization after the requested operation completes. 5. The spender contract, its privileged controller, or an attacker exploiting that contract invokes an authorized token-transfer path. 6. Tokens are transferred from the user's wallet up to its entire current o ...[truncated 695 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Approve only the amount required for the immediate operation: ```ts args: [spenderAddress, requiredAmount] ``` 2. Where token compatibility permits, reset the allowance to zero after the dependent transaction is confirmed. 3. For tokens requiring zero-first allowance changes, submit `approve(spender, 0)` before setting the new exact allowance. 4. Display the token, spender, and approval amount before requesting authorization. 5. Require explicit user confirmation for unusually large or unlimited approvals. 6. Add a command that enumerates and revokes existing allowances. 7. Consider permit-based, transaction-scoped authorization where supported. 8. Document that previously granted unlimited allowances remain active and should be revoked separately. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/commands/buy.ts:31
Finding
Token Trades Lack User-Enforced Slippage and Minimum-Output Protection<![CDATA[ ## Vulnerability Details **File Location**: `src/commands/buy.ts:31-38`; `src/commands/sell.ts:39-46`; `src/commands/sell.ts:74-81` **Vulnerability Type**: Unbounded trade execution price **Risk Level**: Medium ### Vulnerable Code ```ts // src/commands/buy.ts:31-38 log(`Buying FOMO with ${usdtAmount} USDT (wei)...`) const hash = await walletClient.writeContract({ address: FLAP_SKILL_ADDRESS, abi: FLAP_SKILL_ABI, functionName: "buyTokens", args: [fomoToken, usdtAmount], chain: walletClient.chain, }) ``` ```ts // src/commands/sell.ts:39-46 const hash = await walletClient.writeContract({ address: FLAP_SKILL_ADDRESS, abi: FLAP_SKILL_ABI, functionName: "sellTokens", args: [fomoToken, tokenAmount], chain: walletClient.chain, }) ``` ```ts // src/commands/sell.ts:74-81 const hash = await walletClient.writeContract({ address: FLAP_SKILL_ADDRESS, abi: FLAP_SKILL_ABI, functionName: "sellTokensByPercent", args: [fomoToken, percentBps], chain: walletClient.chain, }) ``` ### Technical Analysis The exposed trading calls specify only the input amount or percentage. They do not provide a minimum acceptable output, maximum acceptable price, quote identifier, or deadline. The CLI also does not obtain and validate a quote immediately before submission. As a result, the user cannot express the worst acceptable execution price. If the underlying router does not independently enforce a sufficiently strict bound, a trade may execute after adverse market movement or transaction ordering changes. The audited source cannot establish the internal protections of the deployed `FlapSkill` contract, so the finding concerns the absence of user-controlled protection in the CLI and ABI. ### Attack Path 1. A user submits a buy or sell command based on the currently observed price. 2. The transaction is broadcast without a user-defined minimum return or deadline. 3. Before execution, market conditions change or another transaction changes the relevan ...[truncated 984 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use contract entry points that accept: - A minimum output amount for buys and sells. - A transaction deadline. - Any route or price-bound data required by the underlying exchange. 2. Obtain a fresh on-chain quote before signing. 3. Add a CLI option such as `--slippage-bps`, with a conservative default and an upper safety limit. 4. Calculate `minimumOutput` from the fresh quote and selected tolerance. 5. Simulate the transaction before broadcast and reject execution when the simulation violates the expected bound. 6. Show the expected output, minimum output, effective price, route, and deadline before confirmation. 7. If the deployed intermediary contract cannot support user-defined bounds, replace or upgrade the integration rather than relying solely on an unconstrained trade method. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (36)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The skill is described as game-focused, but it also performs wallet-specific balance inspection and token/Portal state queries using a private key-backed account context. This broadens the effective capability surface beyond the declared behavior and can cause users to expose sensitive wallet credentials for functionality they may not realize is included.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill is described as game-focused, but it also performs wallet-specific balance inspection and token/Portal state queries using a private key-backed account context. This broadens the effective capability surface beyond the declared behavior and can cause users to expose sensitive wallet credentials for functionality they may not realize is included.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill is described as game-focused, but it also performs wallet-specific balance inspection and token/Portal state queries using a private key-backed account context. This broadens the effective capability surface beyond the declared behavior and can cause users to expose sensitive wallet credentials for functionality they may not realize is included.

Known Vulnerable Dependency: ws==8.18.3 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
87% confidence
Finding
The lockfile pins ws 8.18.3, which is flagged for memory disclosure and memory-exhaustion denial-of-service issues. Since viem depends on ws for websocket transport, a skill that interacts with blockchain nodes may open websocket connections to remote endpoints, making malformed or malicious websocket traffic a plausible attack path. In a financial/game CLI, disruption or data leakage around wallet- or chain-interaction channels is more concerning than in a non-networked tool.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly requires a sensitive environment variable (`FOMO3D_PRIVATE_KEY`) yet does not declare a restrictive tool scope or permissions model. In a wallet-signing skill, undeclared access to environment-backed secrets increases the chance that an agent can use private keys without clear user consent boundaries.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill instructs users to provide a raw blockchain private key and notes it may be saved to `config.json`, but it does not prominently warn that this credential grants full control over wallet funds. In the context of a gambling/trading skill that can auto-approve and sign on-chain transactions, insecure handling of the key can lead to total wallet compromise.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Share amounts for `purchase --shares` are **integers** (not wei). 1 share = 1 share.

### Auto-Approve

The CLI automatically checks ERC20 token allowance and approves if needed before `purchase`, `buy`, `sell`, `slot spin`, and `slot deposit`. No manual approval step required.
Confidence
94% confidence
Finding
Automatic ERC-20 approval behavior allows the skill to make spending-authority changes on behalf of the user without a separate manual step. In a financial skill tied to a private key, this reduces user visibility into approvals and can expose funds if allowances are excessive, routed to the wrong contract, or later abused by an external contract.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill describes irreversible on-chain purchases, sales, deposits, and slot bets involving real tokens, but lacks a clear overarching warning about financial loss, slippage, transaction finality, gas costs, and the gambling nature of the actions. Users may treat the CLI as routine automation and authorize costly or unrecoverable actions without understanding the risk.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Pre-checks performed automatically:**
- Game must not be paused
- No pending withdrawal (must `settle` first)
- Token approval (auto-approved if needed)

**Output fields:** `txHash`, `blockNumber`, `status`, `sharesAmount`, `tokensCost` (wei)
Confidence
93% confidence
Finding
The purchase flow states that token approval is auto-executed if needed, bundling authorization changes into a game purchase action. This can mask a distinct asset-control operation from the user and is particularly risky because approvals may persist beyond the immediate transaction.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
```bash
fomo3d buy --amount <usdt_amount_in_wei> --json
```
Buy FOMO tokens using USDT via the FLAP platform. The FlapSkill contract auto-routes to Portal (内盘) or PancakeSwap (外盘) depending on token status. USDT allowance is auto-approved.

**Example:** Buy with 10 USDT:
```bash
Confidence
95% confidence
Finding
Auto-approving USDT for a routing/trading contract is especially sensitive because stablecoin allowances directly expose liquid wallet assets. If the approved contract is compromised, misconfigured, or granted unlimited spending, the user could lose significantly more than the intended trade amount.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- `--amount`: Sell exact token amount (in wei, 18 decimals)
- `--percent`: Sell by percentage of holdings in basis points (10000=100%, 5000=50%, 1000=10%)

Cannot use both flags simultaneously. Token allowance is auto-approved.

**Example:** Sell 50% of holdings:
```bash
Confidence
95% confidence
Finding
Auto-approval in the sell flow can silently expand a contract's authority over the user's token holdings just before liquidation. Combined with percentage-based selling, this increases the risk of unintended large transfers or persistent allowances that outlive the immediate sale.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The shebang uses `npx tsx` without a pinned version, which causes runtime resolution of a package from the npm ecosystem at execution time. This creates a supply-chain risk: a compromised, typosquatted, or newly published incompatible `tsx` version could be fetched and executed, especially on systems without a trusted local install.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
player [--address 0x...]      Player shares, earnings, pending

GAME ACTIONS:
  purchase --shares <n>         Buy shares (auto-approves token)
  exit                          Exit game, claim dividends
  settle                        Settle after round ends + claim prize
  end-round                     End expired round
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.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The help text advertises actions like buying shares, exiting, settling, ending rounds, buying/selling tokens, spinning with a VRF fee, depositing tokens, and claiming funds, but it does not include any user-facing warning that these operations may spend funds, trigger blockchain transactions, or be irreversible. For code files, safety-critical operations should have some visible disclosure unless the warning is already present elsewhere; in this file, the command descriptions are terse and omit transaction-risk warnings.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The command loads a private key and immediately constructs a wallet client capable of signing transactions, but this file provides no user-facing warning, prompt, or explanatory comment about accessing sensitive credentials. For code files, sensitive environment variable or credential access should have some visible disclosure unless clearly documented elsewhere.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code accesses sensitive credential material via requirePrivateKey(config) and uses it to derive the wallet address. In this file there is no confirmation prompt, warning comment, or user-facing log disclosing that a private key will be read when --address is not supplied.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
This command enables users to deposit tokens into the slot game's prize pool and explicitly warns that the funds are permanently locked, which is a high-risk asset-moving capability not reflected in the manifest's narrower slot description. When a skill exposes irreversible on-chain value transfer beyond what a user would reasonably expect from the declared functionality, it creates a dangerous mismatch that can mislead users into authorizing loss of funds.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The file contains user-visible strings and comments in Chinese, including phase labels such as '内盘 (Portal)' and '外盘 (PancakeSwap)', without offering a language choice. This creates a locale policy concern because the skill imposes a specific language on all users rather than allowing opt-in or documenting a justified region-specific constraint.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code persists merged configuration directly to config.json, and the Config schema includes a privateKey field. In a blockchain wallet skill, storing a raw private key unencrypted on disk materially increases the risk of account compromise through local file disclosure, backups, source-control accidents, or other process/user access on the host.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code grants `maxUint256` allowance to the spender whenever the current allowance is insufficient, creating a standing unlimited approval. If the spender contract is compromised, upgraded maliciously, or contains a bug, it can drain all of the user's approved tokens without needing further consent. In this skill context, which actively performs token purchases on BNB Chain, this is more dangerous because users are expected to authorize spending to game-related contracts that may handle real funds.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
Several parts of the document force Chinese terms such as `内盘`, `外盘`, `按数量卖出`, `按持仓比例卖出`, and Chinese-only contract-purpose text, while the rest of the skill is written in English. This creates a language/locale policy issue because users are not given an English-only alternative or explicit opt-in to Chinese terminology.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
All user-facing help and command descriptions in this file are presented only in English, while there is no indication of locale selection or opt-in behavior. Under the stated policy, language constraints should not be forced unless the skill offers a language choice or clearly documents a justified locale restriction.

Known Vulnerable Dependency: esbuild==0.27.3 — 1 advisory(ies): GHSA-g7r4-m6w7-qqqr (esbuild allows arbitrary file read when running the development server on Window)

Low
Category
Supply Chain
Confidence
60% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"start": "tsx bin/fomo3d.ts"
  },
  "dependencies": {
    "tsx": "^4.19.2",
    "viem": "^2.21.0"
  },
  "devDependencies": {
Confidence
88% confidence
Finding
The dependency uses a caret range, which allows installation of newer minor/patch versions than the one reviewed. That creates a supply-chain risk because a compromised or breaking upstream release could be pulled in automatically, and this package executes a CLI that may interact with wallets and blockchain transactions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "tsx": "^4.19.2",
    "viem": "^2.21.0"
  },
  "devDependencies": {
    "typescript": "^5.7.0",
Confidence
89% confidence
Finding
The viem dependency is not pinned exactly, so future installs may resolve to a different version than the one originally tested. In a blockchain-focused skill, dependency drift is more sensitive because library changes can affect transaction construction, signing flows, RPC behavior, or safety checks.

Static analysis

No suspicious patterns detected.