Back to skill

Security audit

Clabcraw

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its game-playing purpose, but it needs review because it can automatically spend or move real USDC and includes unsafe shell-based integration examples.

Install only with a dedicated low-balance wallet, keep the private key out of logs and repositories, set strict local spending limits outside the skill, review the API/RPC endpoints before use, and prefer the GameClient API over the documented execSync CLI examples.

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
docs/AGENT-INTEGRATION.md:135
Finding
Shell Command Injection in Documented CLI Integration<![CDATA[ ## Vulnerability Details **File Location**: `docs/AGENT-INTEGRATION.md:135-139, 168-179, 190-202` **Vulnerability Type**: OS command injection through unescaped shell interpolation **Risk Level**: High ### Vulnerable Code ```javascript import { execSync } from 'child_process' const GAME_TYPE = process.env.CLABCRAW_GAME_TYPE || 'poker' const result = JSON.parse( execSync(`node bins/clabcraw-join --game ${GAME_TYPE}`, { encoding: 'utf-8' }) ) ``` The same unsafe pattern is used with game and action data: ```javascript async function playGame(gameId) { while (true) { const state = JSON.parse( execSync(`node bins/clabcraw-state --game ${gameId}`, { encoding: 'utf-8' }) ) if (state.game_status === 'finished') break if (state.is_your_turn) { const action = decideAction(state) let cmd = `node bins/clabcraw-action --game ${gameId} --action ${action.action}` if (action.amount) cmd += ` --amount ${action.amount}` execSync(cmd, { encoding: 'utf-8' }) } await sleep(500) } } ``` Additional examples repeat the vulnerable construction: ```javascript try { execSync(`node bins/clabcraw-join --game ${GAME_TYPE}`, { encoding: 'utf-8' }) } catch (err) { const body = JSON.parse(err.stderr || '{}') if (body.retry_after_seconds) { await sleep(body.retry_after_seconds * 1000) } } try { execSync(`node bins/clabcraw-action --game ${gameId} --action raise --amount 1`) } catch (err) { const body = JSON.parse(err.stderr || '{}') console.log('Valid actions:', body.valid_actions) } ``` ### Technical Analysis `execSync()` executes a command string through a system shell. The examples directly interpolate values originating from the environment, API responses, or strategy output: - `GAME_TYPE` comes from `CLABCRAW_GAME_TYPE`. - `gameId` can originate from the remote game service. - `action.action` and `action.amount` originate from strategy logic or game state process ...[truncated 1883 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid constructing shell command strings. Use an API that passes executable arguments separately, such as `execFileSync()`: ```javascript import { execFileSync } from 'child_process' const allowedGameTypes = new Set([ 'poker', 'poker-pro', 'poker-novice', 'chess' ]) if (!allowedGameTypes.has(GAME_TYPE)) { throw new Error('Unsupported game type') } const output = execFileSync( process.execPath, ['bins/clabcraw-join', '--game', GAME_TYPE], { encoding: 'utf-8' } ) const result = JSON.parse(output) ``` Apply the following hardening measures: 1. Prefer the non-shell `GameClient` API throughout the documentation. 2. Replace every `execSync(commandString)` example with `execFileSync()` or `spawn()` using an argument array and `shell: false`. 3. Validate game types and action names against explicit allowlists. 4. Validate game IDs against the exact expected UUID format before use. 5. Parse amounts as finite integers and enforce game-specific minimum and maximum values. 6. Never attempt to make command strings safe through ad hoc quoting alone. 7. Add tests using shell metacharacters to verify that supplied values remain literal arguments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
lib/client.js:27
Finding
Automatic x402 Payment Authorization Without Local Spending Constraints<![CDATA[ ## Vulnerability Details **File Location**: `lib/client.js:27-30`; payment-enabled callers at `lib/game.js:82-85` and `lib/game.js:252-258` **Vulnerability Type**: Unbounded automatic cryptocurrency payment authorization **Risk Level**: Medium ### Vulnerable Code The payment client is registered without a local amount, asset, network, recipient, or session-budget policy: ```javascript export function createPaymentFetch(signer) { const client = new x402Client(); registerExactEvmScheme(client, { signer }); return wrapFetchWithPayment(fetch, client); } ``` Paid queue joins automatically use this wrapper: ```javascript async join(gameType) { const data = await this._request( "POST", `/v1/games/join?game=${encodeURIComponent(gameType)}`, null, { usePaymentFetch: true, } ) return { gameId: data.game_id || null, status: data.status, queuePosition: data.queue_position || null, } } ``` Tips use the same automatic payment path: ```javascript async tip(amount = "1.00") { const data = await this._request( "POST", `/v1/platform/tip?amount=${encodeURIComponent(String(amount))}`, null, { usePaymentFetch: true } ) return { donor: data.donor, amountUsdc: data.amount_usdc, tx: data.tx, } } ``` ### Technical Analysis When a payment-enabled request receives an HTTP 402 response, `wrapFetchWithPayment()` is allowed to use the wallet signer to create a payment authorization and retry the request. The project does not independently validate the payment terms before signing. In particular, the code does not locally enforce: - A maximum payment amount. - An expected token contract or asset. - An expected recipient or facilitator. - An expected blockchain network. - A per-game, per-request, or cumulative session budget. - Owner confirmation above a configurable threshold. This trust boundary is significant because `CLABCRAW_API_URL` is configurable and is used to construct the de ...[truncated 1764 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Introduce an explicit payment-policy layer before any x402 terms are signed: 1. Enforce a maximum amount for each operation, with separate limits for game entry and tips. 2. Require the offered asset to match the expected USDC contract on the selected Base network. 3. Require the network and chain ID to match an explicit allowlist. 4. Validate the payment recipient or facilitator against trusted configured addresses. 5. Track cumulative spending and enforce per-session and daily budgets. 6. Require interactive owner confirmation when a payment exceeds a configured threshold. 7. Bind the accepted payment amount to the fee previously displayed to the user, while also applying an independent local cap. 8. Reject payment requests after redirects to an unexpected origin. 9. Default to HTTPS for payment-enabled production endpoints and reject insecure HTTP except under an explicit local-development mode. 10. Record structured audit logs containing the approved amount, token, network, recipient, operation, and transaction identifier without logging private keys or sensitive signatures. Where supported by the x402 library, configure native payment selectors or policy callbacks. Otherwise, inspect and validate the HTTP 402 payment requirements before passing them to a signing-capable client. ]]>
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (42)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code does operate on the Clabcraw platform and participates in USDC-based matches, so it is related to the declared domain. However, the declared description is broad and implies a normal-purpose 1v1 game competitor, while the actual code is specifically a poker auto-play script designed for quick local/testing-style games. Its primary behavior is materially narrower and different: it only targets poker and deliberately switches to an all-in strategy after the first five hands to finish games fast. That undisclosed game-specific and quick-play behavior makes the description inaccurate.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description says the skill competes in 1v1 games on the Clabcraw arena, but this code does not contain any game interaction or gameplay logic. Instead, it implements payment and signing utilities: it converts a private key into a viem account and creates a fetch wrapper that automatically handles x402 payment flows by signing USDC authorizations when a server responds with 402 Payment Required. That is a materially different primary purpose from playing Clabcraw matches. While payment support could be a supporting detail for a USDC-based arena, this chunk is purely payment infrastructure and cryptographic signing, not competition logic, so the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code does support the declared core purpose of competing in Clabcraw 1v1 games for USDC: it joins games, retrieves game state, submits actions, and runs a game loop. However, it also includes materially additional financial and platform-management capabilities not reflected in the description, notably tipping the platform, checking claimable balances, and executing on-chain claim transactions through a wallet client. These are beyond merely competing in games and should be declared if this description is meant to accurately represent the skill’s behavior. Declared permissions are empty, yet the code uses a private key, makes signed requests, performs payment-enabled requests, and can submit blockchain transactions; while permission mismatch alone is not the main criterion, these behaviors reinforce that the implementation is broader than the stated purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose is a game-playing skill for the Clabcraw arena involving 1v1 competition for USDC. The provided code chunk does not implement gameplay, arena interaction, wallet/payment handling, or any trigger logic. Instead, it provides generic logging utilities. While logging can be a supporting implementation detail, this chunk alone does not reflect the declared purpose and is materially unrelated in primary behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description suggests an active skill that competes in Clabcraw 1v1 games for USDC. However, this code chunk only contains local data-transformation helpers: parsing card strings, normalizing valid actions, and converting a raw game-state response into a cleaner object. It does not initiate or join games, submit moves, handle wallets/USDC, call external services, or otherwise perform competition behavior. While this code could support such a skill as an internal helper, by itself it does not accurately represent the declared primary purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose describes gameplay functionality on the Clabcraw arena, likely involving participating in 1v1 USDC games. However, the supplied code chunk does not implement gameplay or arena interaction at all. It only reads local files and runs tests to ensure that contract address values are consistent between configuration sources. This is a materially different primary purpose from the declared description, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description says the skill competes in 1v1 games on the Clabcraw arena for USDC. However, the provided code chunk is only a test suite for error classes and HTTP response mapping in lib/errors.js. It checks behavior for statuses like 400, 401, 402, 404, 422, 500, and 503, plus retry timing and specialized errors such as paused, insufficient funds, and invalid action. While this may support a larger Clabcraw client, this specific code does not perform gameplay, place wagers, interact with arena matches, or handle game turns beyond testing error objects. Therefore the actual behavior does not match the declared primary purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This code chunk does not implement a game-playing skill. It only contains tests for helper functions (`parseCard`, `normalizeState`) that transform card and state data into normalized structures. There is no network access, no trigger handling, no betting or wallet logic, and no action-selection code to compete in 1v1 matches. While the tested schema relates to card-game state, that is only a supporting data-model concern and does not match the declared primary purpose of actively competing on Clabcraw for USDC.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose suggests an operational skill that participates in 1v1 games on the Clabcraw arena involving USDC. However, the actual code chunk contains only tests for a poker strategy library. It exercises functions like handRank, estimateEquity, potOdds, shouldCall, suggestBetSize, countOuts, and findAction. There is no code showing connection to Clabcraw, no arena/gameplay integration, no blockchain or USDC handling, no triggers, and no logic specific to 1v1 competition on that platform. The primary purpose of the code is materially different from the declared description, so this is a clear mismatch.

Ae1

High
Category
analysis-evasion
Content
The best way to run this skill is using **GameClient** from `lib/game.js`. It handles all coordination automatically — joining, matching, state polling, and gam
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
The best way to run this skill is using **GameClient** from `lib/game.js`. It handles all coordination automatically — joining, matching, state polling, and gam
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
Or store in a `.env` file (never commit to git):

```bash
# .env
CLABCRAW_WALLET_PRIVATE_KEY=0x...
```
Confidence
87% confidence
Finding
Advising users to place a blockchain private key in a local .env file creates a straightforward credential-exposure path if the file is copied, logged, backed up, or accidentally committed. Because the credential directly controls funds, compromise can immediately lead to wallet takeover and financial loss.

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
95% confidence
Finding
The lockfile pins transitive dependency ws to version 8.18.3, and the supplied finding indicates known advisories affecting that exact version, including memory disclosure and memory-exhaustion denial of service. In a skill that interacts with blockchain/network services, WebSocket usage is plausible via viem, so a vulnerable ws package can expose the agent to remote attack surface if it connects to untrusted or attacker-influenced endpoints.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares capabilities that require environment access and outbound network use, including a wallet private key and API calls, but does not declare any tool scope or permissions boundary. In an agent platform, this increases the chance the skill runs with broader-than-necessary privileges and makes review, sandboxing, and user consent weaker.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The quick-start path says joining the queue pays an entry fee via x402, but it does not provide a prominent warning that real funds will be spent automatically when the command runs. In an agent setting, insufficient spending disclosure can lead to unintentional financial loss, especially if auto-play is launched with a funded wallet.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The wallet setup instructions print the private key to stdout, store it in a plaintext file, and then display the file contents with cat. Even though file permissions are tightened, these steps materially increase the chance of credential exposure through shell history, terminal logs, screenshots, backups, or agent execution logs, and compromise would enable theft of USDC and wallet control.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Option 1: Generate a new wallet (recommended for automation)

```bash
mkdir -p ~/.clabcraw && chmod 700 ~/.clabcraw

node -e "
import { generatePrivateKey, privateKeyToAddress } from 'viem'
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
### Option 1: Generate a new wallet (recommended for automation)

```bash
mkdir -p ~/.clabcraw && chmod 700 ~/.clabcraw

node -e "
import { generatePrivateKey, privateKeyToAddress } from 'viem'
Confidence
84% confidence
Finding
The instructions create a persistent directory under the user's home folder and store wallet material there for reuse across sessions. Persistent storage of a high-value private key expands the exposure window and increases the blast radius of any later host compromise, log leak, or backup leak.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
console.log('Private Key:', key)
" > ~/.clabcraw/wallet-key.txt

chmod 600 ~/.clabcraw/wallet-key.txt
cat ~/.clabcraw/wallet-key.txt

# Load it:
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The guide instructs users to provide a wallet private key via environment variables without clearly flagging that this is a highly sensitive credential controlling on-chain funds. In agent and automation environments, environment variables are frequently exposed through logs, process inspection, crash reports, CI systems, or inherited subprocesses, increasing the risk of wallet compromise and theft.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The integration guide shows agents how to automatically join paid games, claim winnings, and send tips using real USDC, but it does not prominently warn that these actions spend or move real funds. In an agent context, examples are often copied directly into autonomous workflows, so this can lead to unintended financial transactions, repeated paid actions, or unauthorized value transfer if the agent is triggered incorrectly.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The documentation instructs users to run a queue-join command that pays a USDC entry fee and requires a wallet private key, but it does not provide an explicit warning that executing the command authorizes spending real funds. In an agent-skill context, this is especially risky because an autonomous system may invoke the command as part of normal operation, causing unintended financial loss or repeated paid joins without meaningful user consent.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation describes a claim command that withdraws all claimable USDC on-chain using a wallet private key, but it lacks a clear caution that this initiates a blockchain transaction, consumes gas, and moves assets. In an agent environment, this can lead to unauthorized transfers, accidental claims to the wrong wallet or network configuration, and unnecessary gas expenditure if invoked automatically.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The example directly calls `game.claim()` and logs a transaction hash in a troubleshooting context without an explicit warning that this initiates a real on-chain withdrawal. In a skill centered on real-money USDC gameplay, readers may copy-paste recovery snippets into production agents and unintentionally trigger fund-moving transactions when they only intended to inspect balances or debug failures.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This queue-leave example automatically follows cancellation with `game.claim()` after checking for a positive balance, but does not clearly warn that the call performs a real on-chain withdrawal. Because the skill operates in a financial setting using USDC, such documentation can normalize automatic fund-moving behavior in agent code and increase the risk of unintended transactions, gas expenditure, or premature withdrawals.

Static analysis

No suspicious patterns detected.