Back to skill

Security audit

Solana Transfer

Security checks for vulnerabilities and agentic risk

Overview

This skill is not deceptive, but it can move real Solana funds immediately from a local wallet without adequate approval or limits.

Only install this for wallets and environments where agent-driven spending is acceptable. Prefer devnet/testnet first, use a low-balance dedicated wallet, add explicit per-transaction approval, recipient allowlists, spend caps, strict amount validation, and dependency updates before using it with real funds.

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
index.js:60
Finding
Unsafe and Non-Canonical Transaction Amount Parsing## Vulnerability Details **File Location**: `index.js`, lines 60-69 and 104-116 **Vulnerability Type**: Improper input validation and unsafe numeric conversion **Risk Level**: High ### Vulnerable Code ```javascript async function sendSOL(recipientAddress, lamports) { const recipient = new PublicKey(recipientAddress); const sender = keypair.publicKey; const transaction = new Transaction().add( SystemProgram.transfer({ fromPubkey: sender, toPubkey: recipient, lamports: parseInt(lamports), }) ); ``` ```javascript // Send tokens const signature = await transfer( connection, keypair, senderTokenAccount.address, recipientTokenAccount.address, keypair, parseInt(amount) // assumes amount is in smallest unit (lamports for USDC, etc) ); ``` ### Technical Analysis Both transaction functions convert payment amounts with `parseInt` without first validating that the complete input is a canonical positive integer. This conversion is permissive: an input such as `1000000abc` is interpreted as `1000000`, while decimal values are silently truncated. The code also converts amounts to JavaScript `number` values without enforcing the `Number.MAX_SAFE_INTEGER` boundary. Large integer strings can therefore lose precision before transaction construction. No explicit minimum, maximum, balance-based policy, per-transaction limit, or confirmation control is enforced. This issue affects both the command-line interface and the exported programmatic API. Any Agent workflow that supplies amounts derived from untrusted quotes, messages, or generated content may authorize a value different from the exact value supplied by the caller. ### Attack Path 1. An attacker or untrusted Agent response supplies a crafted payment amount to a workflow using this Skill. 2. The workflow passes the value to `sendSOL`, `sendSPLToken`, `send-sol`, or `send-token` without independent validat ...[truncated 777 chars]
Remediation
## Remediation Suggestions - Accept amounts only as digit-only strings or `bigint` values. - Reject empty, signed, decimal, exponential, hexadecimal, trailing-character, zero, and negative values. - Avoid conversion to JavaScript `number` when the Solana API supports `bigint`. - If a number is unavoidable, require `Number.isSafeInteger(value)` and `value > 0`. - Define explicit per-transaction and daily transfer limits. - Verify that the requested amount and expected fees are within the wallet balance. - Require an independent recipient-and-amount approval step before signing high-value transactions. - Use a validation pattern such as: ```javascript function parsePositiveAmount(value) { const text = String(value); if (!/^[0-9]+$/.test(text)) { throw new TypeError('Amount must be a positive integer in smallest units'); } const amount = BigInt(text); if (amount <= 0n) { throw new RangeError('Amount must be greater than zero'); } return amount; } ```

T09 · Insecure Skill Coding Practices

Error
Location
index.js:194
Finding
CLI Execution Occurs Automatically When the Module Is Imported## Vulnerability Details **File Location**: `index.js`, lines 194-196 **Vulnerability Type**: Import-time side effect enabling unintended transaction execution **Risk Level**: High ### Vulnerable Code ```javascript main(); export { sendSOL, sendSPLToken, connection, keypair }; ``` The invoked function reads the process-wide command-line arguments: ```javascript async function main() { const [command, ...args] = process.argv.slice(2); try { if (command === 'send-sol') { const [recipient, amount] = args; if (!recipient || !amount) { console.error('Usage: node index.js send-sol <recipient-address> <lamports>'); process.exit(1); } const result = await sendSOL(recipient, amount); console.log(JSON.stringify(result, null, 2)); } else if (command === 'send-token') { const [recipient, tokenMint, amount] = args; if (!recipient || !tokenMint || !amount) { console.error( 'Usage: node index.js send-token <recipient-address> <token-mint> <amount>' ); process.exit(1); } const result = await sendSPLToken(recipient, tokenMint, amount); console.log(JSON.stringify(result, null, 2)); } ``` ### Technical Analysis The same file is documented and exported as a reusable library, but it invokes `main()` unconditionally. ES module imports execute top-level statements, so importing `sendSOL` or `sendSPLToken` also starts the CLI handler. The CLI handler interprets the host application's `process.argv`, not arguments scoped to this module. If an importing process was launched with arguments beginning with `send-sol` or `send-token`, the import can sign and broadcast a payment without the importing code explicitly calling a transfer function. The side effect can also invoke `process.exit(1)` during an import, allowing malformed arguments or transaction er ...[truncated 1185 chars]
Remediation
## Remediation Suggestions - Separate the reusable library and CLI into different files. - Keep key loading and transaction functions in a side-effect-free module. - Place `main()` in a dedicated executable, such as `cli.js`. - Alternatively, invoke `main()` only when `index.js` is the direct entry point. - Do not call `process.exit` from code paths reachable through a library import; throw typed errors instead. - Add an automated test that imports the module with transfer-like command-line arguments and verifies that no transaction function is invoked. Example direct-execution guard: ```javascript import { pathToFileURL } from 'url'; if (import.meta.url === pathToFileURL(process.argv[1]).href) { main().catch((error) => { console.error('Error:', error.message); process.exitCode = 1; }); } export { sendSOL, sendSPLToken, connection, keypair }; ```

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:79
Finding
Failed SOL Transactions Can Be Reported as Successful## Vulnerability Details **File Location**: `index.js`, lines 79-90 **Vulnerability Type**: Improper transaction confirmation result handling **Risk Level**: Medium ### Vulnerable Code ```javascript const signature = await connection.sendTransaction(transaction, [keypair]); const confirmation = await connection.confirmTransaction(signature); return { success: true, signature, amount: (lamports / 1e9).toFixed(9), unit: 'SOL', recipient: recipientAddress, confirmation, }; ``` ### Technical Analysis The SOL transfer function returns `success: true` after receiving a confirmation response but does not inspect `confirmation.value.err`. Transaction confirmation and successful transaction execution are distinct conditions: a transaction can reach the selected commitment level while containing an execution error. Downstream Agent workflows may trust the explicit `success` field and release goods, services, rewards, or task results even when the transfer failed. The function also confirms using only the signature rather than retaining and supplying the blockhash and last-valid-block-height context obtained before submission. ### Attack Path 1. A payment workflow calls `sendSOL` and uses the returned `success` field as proof of payment. 2. The submitted transaction is confirmed but fails during execution. 3. `confirmTransaction` returns a response whose error field indicates failure. 4. The Skill does not inspect that field and returns `success: true`. 5. The calling Agent treats the payment as completed and continues its business workflow. 6. A service, reward, or other asset may be delivered even though the recipient did not receive the SOL. Exploitation depends on a workflow trusting the returned status without independently verifying the transaction on-chain. The failure may be deliberately induced where transaction conditions can be manipulated, or it may arise from ordinary network and execut ...[truncated 303 chars]
Remediation
## Remediation Suggestions - Inspect the transaction confirmation error field and throw when it is non-null. - Return `success: true` only after successful execution has been established. - Confirm with the blockhash and last-valid-block-height strategy. - Optionally fetch the finalized transaction and verify its metadata before treating payment as settled. - Require downstream workflows to validate the signature, sender, recipient, amount, mint, and final execution status independently. Example: ```javascript const latest = await connection.getLatestBlockhash(); transaction.recentBlockhash = latest.blockhash; const signature = await connection.sendTransaction(transaction, [keypair]); const confirmation = await connection.confirmTransaction( { signature, blockhash: latest.blockhash, lastValidBlockHeight: latest.lastValidBlockHeight, }, 'confirmed' ); if (confirmation.value.err !== null) { throw new Error( `Transaction failed: ${JSON.stringify(confirmation.value.err)}` ); } return { success: true, signature, confirmation, }; ```
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (12)

Missing User Warnings

High
Confidence
95% confidence
Finding
The SOL transfer function signs and submits a live transfer directly from the configured wallet as soon as it is invoked, without any explicit confirmation, preview, or human approval. Because blockchain transfers are generally irreversible, exposing this as an agent skill materially increases the risk of prompt-triggered, accidental, or unauthorized fund movement from the loaded keypair.

Missing User Warnings

High
Confidence
93% confidence
Finding
The token transfer path can both create the recipient’s associated token account and transfer assets immediately using the locally loaded signing key, with no confirmation step, policy gate, allowlist, dry-run, or user acknowledgement. In an agent skill context, this is especially dangerous because untrusted prompts, tool calls, or accidental parameterization can trigger irreversible on-chain spending and also incur extra SOL costs for account creation.

Known Vulnerable Dependency: bigint-buffer==1.1.5 — 1 advisory(ies): CVE-2025-3194 (bigint-buffer Vulnerable to Buffer Overflow via toBigIntLE() Function)

High
Category
Supply Chain
Confidence
96% confidence
Finding
The lockfile includes bigint-buffer 1.1.5, which is reported as vulnerable to a buffer overflow in toBigIntLE(). Even though this is a transitive dependency, memory-safety issues in native/binary-adjacent parsing code can lead to crashes or potentially worse behavior when processing attacker-controlled input.

Known Vulnerable Dependency: ws==8.19.0 — 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
97% confidence
Finding
The lockfile includes ws 8.19.0 with advisories for uninitialized memory disclosure and memory exhaustion DoS. Because @solana/web3.js depends on rpc-websockets, a network-facing blockchain client may process remote websocket traffic, making these flaws materially relevant in this skill context.

Known Vulnerable Dependency: ws==7.5.10 — 1 advisory(ies): CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
96% confidence
Finding
The lockfile also contains ws 7.5.10, flagged for a memory exhaustion DoS issue from fragmented websocket frames. Since jayson depends on ws 7.x and may be used in JSON-RPC communication paths, an attacker interacting with exposed websocket functionality could force excessive resource consumption and degrade service availability.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README gives concrete commands for sending SOL and SPL tokens, including mainnet configuration, but does not prominently warn that blockchain transfers are irreversible and may spend real funds. In an agent skill context, this increases the chance that operators or downstream agents invoke payment actions against production wallets without understanding that mistakes cannot be rolled back.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill is explicitly designed to initiate irreversible on-chain SOL and SPL token transfers, and the documentation encourages direct agent integration with examples that call sendSOL/sendSPLToken automatically. While it includes a brief note to verify recipients and amounts, it does not require explicit per-transaction human approval, spending limits, or a strong upfront warning that using the skill can move real funds immediately and irreversibly, which creates a meaningful risk of accidental or prompt-induced fund loss.

Known Vulnerable Dependency: bn.js==5.2.2 — 1 advisory(ies): CVE-2026-2739 (bn.js affected by an infinite loop)

Low
Category
Supply Chain
Confidence
88% confidence
Finding
The project resolves bn.js 5.2.2, which is flagged for an infinite-loop condition. If untrusted numeric input reaches the affected code paths, an attacker could trigger CPU exhaustion or a hung process, though the impact is generally limited to denial of service rather than code execution.

Known Vulnerable Dependency: stream-json==1.9.1 — 1 advisory(ies): CVE-2026-71429 (stream-json: pick/ignore/filter/replace filters are O(depth²) on nested input — )

Low
Category
Supply Chain
Confidence
84% confidence
Finding
stream-json 1.9.1 is flagged for O(depth²) behavior in certain filters on deeply nested input, which can enable denial of service through pathological JSON structures. In this lockfile it is transitive via jayson, so exploitability depends on whether attacker-controlled nested JSON reaches those specific parsing/filter paths.

Known Vulnerable Dependency: uuid==8.3.2 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
81% confidence
Finding
uuid 8.3.2 is reported to lack buffer bounds checks in some versioned UUID generation helpers when a buffer is supplied. This can cause runtime faults or unintended memory writes within JavaScript buffer handling paths, but typically requires a specific application usage pattern and has relatively constrained impact.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"test": "node test.js"
  },
  "dependencies": {
    "@solana/web3.js": "^1.87.0",
    "@solana/spl-token": "^0.4.3"
  },
  "keywords": ["solana", "web3", "tokens", "blockchain"]
Confidence
91% confidence
Finding
The dependency uses a caret range, which allows npm to install newer compatible versions automatically. This increases supply-chain risk because a compromised or breaking upstream release could be pulled in without explicit review, which is especially relevant for a blockchain transfer skill that handles transactions and potentially valuable assets.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "@solana/web3.js": "^1.87.0",
    "@solana/spl-token": "^0.4.3"
  },
  "keywords": ["solana", "web3", "tokens", "blockchain"]
}
Confidence
91% confidence
Finding
The dependency is specified with a caret range, permitting automatic adoption of future patch/minor releases. In a financial or wallet-related skill, this can expose the project to supply-chain compromise or unexpected behavior from upstream package changes without deliberate validation.

Static analysis

No suspicious patterns detected.