Back to skill

Security audit

A2A Decentralized Prediction Market on Solana

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned, but it should be reviewed carefully because it guides agents to sign real-money Solana transactions supplied by a remote API without enough transaction validation or spending guardrails.

Use only a dedicated low-balance Solana wallet, review every transaction in a wallet UI before signing, set hard per-bet and daily limits, avoid autonomous repeated betting, and treat API market data, comments, and votes as service-mediated rather than fully on-chain authoritative.

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
SKILL.md:210
Finding
Blind Signing of Remote Server-Supplied Solana Transactions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:210-233` **Vulnerability Type**: Unvalidated transaction signing **Risk Level**: High ### Vulnerable Code ```typescript async function executeAction(prepareUrl: string, submitUrl: string, body: object, keypair: Keypair) { const authHeaders = createAuthHeaders(keypair); // Step 1: Prepare (requires auth) const prepRes = await fetch(prepareUrl, { method: 'POST', headers: { ...authHeaders }, body: JSON.stringify(body), }); const { data } = await prepRes.json(); // Step 2: Sign const tx = Transaction.from(Buffer.from(data.transaction, 'base64')); tx.sign(keypair); // Step 3: Submit const submitRes = await fetch(submitUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ signedTransaction: tx.serialize().toString('base64'), }), }); return await submitRes.json(); } ``` ### Technical Analysis The function obtains a serialized transaction from a remote `prepareUrl`, deserializes it, and signs it with the wallet keypair without validating the transaction contents. No checks ensure that: - Every instruction invokes the documented ChronoBets program ID. - Token instructions use the documented Solana mainnet USDC mint. - Writable and signer accounts match the requested operation. - Token and SOL transfer destinations are expected. - Transfer amounts, platform fees, creator fees, and stakes match the user's request. - The market identifier and outcome correspond to the requested action. - The transaction contains no additional or unrelated instructions. - The transaction has been simulated successfully. - The user has approved the exact financial consequences. Base64 decoding is not local code or shell execution, so the pre-scan's decode-and-execute indicator does not represent arbitrary code execution. Nevertheless, signing an untrusted serialized blockchain transaction authorizes the instructions embedd ...[truncated 1907 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Implement a fail-closed transaction-verification layer before signing: 1. **Restrict API destinations** - Do not accept arbitrary `prepareUrl` and `submitUrl` values. - Construct URLs from a fixed, allowlisted HTTPS origin. - Reject redirects to other origins. 2. **Allowlist programs** - Require ChronoBets instructions to target the documented program ID: `8Lut48u2M5eFjnebP1KowRKytAFDHKvFA11UPR2Y3dD4`. - Permit System Program, Compute Budget, Associated Token Account, and SPL Token instructions only where specifically required. - Reject every unknown program or unexpected instruction. 3. **Validate instruction semantics** - Decode each ChronoBets instruction and verify its discriminator and arguments. - Confirm the market ID, outcome, stake, bet amount, and minimum shares against the original request. - Verify all signer and writable accounts. - Recompute and verify expected PDAs. 4. **Validate financial effects** - Require the documented USDC mint: `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`. - Check token source accounts, destination accounts, treasury, creator, and vault addresses. - Reject transfers exceeding the user-approved amount and fee tolerance. - Reject authority changes, delegate approvals, account closures, and unrelated SOL transfers. 5. **Simulate before signing** - Simulate the transaction using a trusted Solana RPC endpoint. - Compare pre- and post-transaction token balances. - Abort on unexpected logs, programs, account mutations, or balance changes. 6. **Require explicit approval** - Present the exact asset, amount, fees, recipients, market, outcome, and maximum loss. - Require explicit user confirmation for every real-money transaction. - Never autonomously create markets, bet, or challenge outcomes without a user-defined spending policy. 7. **Use wallet isolation** - Use a dedicated low-balance wallet rather than a general-pu ...[truncated 78 chars]

T09 · Insecure Skill Coding Practices

Warning
Location
references/api-reference.md:496
Finding
Betting Example Disables Effective Slippage Protection<![CDATA[ ## Vulnerability Details **File Location**: `references/api-reference.md:496-525` **Vulnerability Type**: Unsafe financial transaction configuration **Risk Level**: Medium ### Vulnerable Documentation ```markdown ### POST /api/v1/bets/prepare -- Auth: Yes Prepare a buy-shares transaction. **Request Body:** ```json { "agentWallet": "base58-pubkey", "marketId": 42, "outcomeIndex": 0, "amount": 5, "minShares": 0 } ``` - `agentWallet`: Must match authenticated wallet - `amount`: USDC in dollars (e.g., 5 = $5). Minimum: 1, Maximum: 1,000,000. - `outcomeIndex`: 0-based index into the market's outcomes array. - `minShares`: Optional slippage protection (minimum shares to receive). ``` ### Technical Analysis The example sets `minShares` to zero even though the on-chain `buy_shares` instruction only requires the actual share output to be greater than or equal to this value. A zero minimum therefore provides no meaningful lower bound on execution quality. The transaction can remain valid even if the expected share output declines materially between preparation and execution. This may occur because of concurrent bets, stale read-replica data, delayed submission, transaction ordering, or an inaccurate quote. Because bets use real USDC on Solana mainnet, a permissive zero value is an unsafe default. Slippage protection should be derived from `estimatedShares` and a user-approved tolerance rather than presented as optional or disabled in the primary request example. ### Attack Path 1. The agent follows the documented example and requests a bet with `minShares: 0`. 2. The prepare endpoint returns a transaction based on the current pool state. 3. Other transactions alter the pool before the prepared transaction executes, or an adversary exploits transaction ordering around the bet. 4. The effective share output becomes materially worse than the original estimate. 5. The on-chain check still passes because the output remains greater than or equal t ...[truncated 590 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `minShares: 0` with a nonzero value calculated from the quote: ```typescript const slippageBps = 100; // Example: 1%, subject to user approval const minShares = estimatedShares * (10_000 - slippageBps) / 10_000; ``` 2. Require users to approve a maximum slippage tolerance before preparing the transaction. 3. Reject zero `minShares` values for real-money bets unless the user explicitly opts into an unbounded market order after receiving a prominent warning. 4. Associate quotes with a short expiration time and re-prepare the transaction when the quote expires. 5. Simulate immediately before signing and compare the expected share output against `minShares`. 6. Display the following information before approval: - USDC amount spent. - Estimated shares. - Minimum guaranteed shares. - Effective price. - Platform and creator fees. - Maximum permitted slippage. 7. Abort when the simulation or decoded transaction does not contain the approved nonzero minimum-shares constraint. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill metadata says all operations use real USDC on Solana mainnet, but the document also exposes non-financial off-chain features such as comments and voting. This mismatch can mislead downstream agents or users about what actions are purely on-chain versus what data and interactions are handled by a centralized web service, weakening informed consent and trust boundaries.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This skill enables real-money betting and market creation on Solana mainnet with real USDC, but it does not prominently warn about financial loss, irreversible blockchain transactions, or the need for explicit user confirmation before spending funds. In the context of an autonomous agent skill, omission of these warnings increases the chance of accidental or overly broad authorization for risky transactions.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# 1. Prepare the registration transaction
curl -X POST https://chronobets.com/api/v1/agents/prepare \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: YOUR_WALLET_PUBKEY" \
  -H "X-Signature: <base58-signature>" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Phase 1: Propose Outcome** (after market closes, auth headers required)
```bash
curl -X POST https://chronobets.com/api/v1/markets/propose/prepare \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: YOUR_WALLET" \
  -H "X-Signature: <base58-signature>" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#### Oracle Markets (automatic)
```bash
curl -X POST https://chronobets.com/api/v1/markets/resolve/prepare \
  -H "Content-Type: application/json" \
  -H "X-Wallet-Address: ANY_WALLET" \
  -H "X-Signature: <base58-signature>" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The lifecycle section encourages a loop of funding, betting, monitoring, claiming, and repeating without guardrails around bankroll limits, cooling-off checks, or explicit approval for each wager. In a gambling-focused skill operating with real USDC, this can normalize autonomous repeated spending and magnify financial harm from user misunderstanding or agent misbehavior.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The authentication scheme references a different service name ('MoltBets') than the documented platform ('ChronoBets'). In a wallet-signature-based authentication flow, domain/service binding in the signed message is important context for users and integrators; inconsistent branding can enable signature confusion, accidental credential reuse across services, and phishing-style abuse where a signature intended for one service is accepted by another.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This documentation describes many real-money, irreversible Solana mainnet operations—market creation, betting, disputes, resolution, and claims—without prominent safety guidance about financial loss, finality, signature review, or transaction consequences. In an agent-skill context, that omission is dangerous because downstream agents may present these actions as routine API calls and induce users to sign value-transferring transactions without informed consent or adequate review.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The reference documentation states `oracle_type` supports `2=Switchboard` while separately declaring `Switchboard (not implemented)`. In a skill that drives real USDC interactions on Solana mainnet, this inconsistency can cause an agent or integrator to attempt unsupported oracle-based market creation or resolution flows, leading to failed transactions, stuck markets, or incorrect trust assumptions about how outcomes are resolved.

Description-Behavior Mismatch

Low
Confidence
97% confidence
Finding
The statement 'All data is on-chain' is contradicted by the later architecture section describing a read-replica database and webhook-based synchronization. This can cause agents to overtrust API responses as canonical blockchain state when they may actually be stale, incomplete, or centrally controlled replicas.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The documentation presents the platform as entirely on-chain while later documenting off-chain storage and social features. In a financial skill, this inconsistency is security-relevant because it obscures which trust assumptions apply to fetched data and user interactions.

Static analysis

No suspicious patterns detected.