Back to skill

Security audit

Solana Batch Payments

Security checks for vulnerabilities and agentic risk

Overview

This skill is for real Solana batch payments and is mostly transparent, but its helper can sign and broadcast gateway-supplied transactions without validating what they do.

Review this carefully before installing. Use devnet first, avoid the unpinned MCP npx command unless you independently trust and pin the package, and do not use the signing helper with valuable wallets unless you decode and verify each transaction's recipients, amounts, mint, fees, programs, and fee payer before signing.

Vulnerability Patterns
  • 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
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/sign-and-send.js:29
Finding

Untrusted Gateway Transactions Are Signed Without Instruction Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/sign-and-send.js:29-48
Vulnerability Type: Blind signing of externally supplied blockchain transactions
Risk Level: High

Vulnerable Code

js
const res = JSON.parse(readFileSync(responsePath, 'utf8'));
const secret = Uint8Array.from(JSON.parse(readFileSync(keypairPath, 'utf8')));
const keypair = Keypair.fromSecretKey(secret);

if (res.sender && keypair.publicKey.toBase58() !== res.sender) {
  console.error(`Keypair ${keypair.publicKey.toBase58()} does not match sender ${res.sender}`);
  process.exit(1);
}

const connection = new Connection(
  rpcUrl || 'https://api.mainnet-beta.solana.com',
  'confirmed',
);

console.log(`Signing ${res.transactionCount} transaction(s) as ${keypair.publicKey.toBase58()}`);

for (const [i, b64] of res.transactions.entries()) {
  const tx = Transaction.from(Buffer.from(b64, 'base64'));
  tx.sign(keypair);

  try {
    const sig = await connection.sendRawTransaction(tx.serialize());

Technical Analysis

The helper treats every serialized transaction in an external response file as trusted. It deserializes, signs, and broadcasts each transaction without inspecting its instructions or confirming that they match the user's intended payment operation.

The existing sender check is insufficient because:

  • res.sender is optional; the check is skipped if that response field is absent.
  • The check validates response metadata rather than the serialized transaction's fee payer and required signers.
  • It does not validate recipients, transfer amounts, token mint, fee recipient, fee amount, program IDs, or additional instructions.
  • It does not bind the transaction to a locally retained copy of the original request.
  • It does not reject unknown or dangerous program instructions.

Solana transaction signatures authorize the serialized message, not the human-readable response metadata. Therefore, ...[truncated 1682 chars]

Remediation
View remediation

Remediation Suggestions

Implement fail-closed transaction verification before signing:

  1. Require res.sender and reject responses where it is missing.
  2. Verify the serialized transaction's fee payer and required signer set directly.
  3. Retain the original local request and compare every transaction instruction against it.
  4. Decode and validate all recipient addresses, transfer amounts, token mints, associated-token-account creation instructions, and service fees.
  5. Allow only explicitly approved Solana program IDs and instruction types.
  6. Reject unknown, additional, duplicated, or reordered instructions that are not expected by the validated transaction model.
  7. Verify that the transaction blockhash matches the expected response and is current.
  8. Independently calculate totals across all transaction chunks and ensure they match the user's approved batch.
  9. Display a deterministic transaction summary, including recipients, assets, totals, fees, and program IDs.
  10. Require explicit user confirmation after validation and before signing or broadcasting.
  11. Where practical, simulate the transaction through a trusted RPC and inspect the simulation result before requesting approval.
  12. Add adversarial tests covering omitted sender metadata, extra instructions, altered recipients, excessive fees, unknown programs, and mismatched mints.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:117
Finding

Unpinned npm Package Is Downloaded and Executed Through npx

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:117-121
Vulnerability Type: Unpinned third-party dependency execution
Risk Level: Medium

Vulnerable Code

markdown
## MCP option

Prefer tools over raw HTTP? The gateway ships an MCP server:

```bash
npx -y spraay-x402-mcp   # main gateway, 183 tools incl. all Solana endpoints

Or from source: node mcp/spraay-solana-mcp.js

text

### Technical Analysis

The documented command uses `npx -y` to resolve, download, and immediately execute the current registry version of `spraay-x402-mcp`. No exact version, integrity hash, lockfile, or reviewed local artifact is specified.

The `-y` option suppresses the installation confirmation, reducing the opportunity for the user to inspect what will be installed. npm packages may execute runtime code and, depending on npm configuration, lifecycle scripts with the permissions of the invoking user.

The MCP package reportedly exposes 183 tools, which substantially expands the network and operational capability beyond the Skill's core batch-payment function. This broad capability is not necessary when the user only needs the included signing helper or a small subset of gateway operations.

### Attack Path

1. A user or Agent follows the MCP command from `SKILL.md`.
2. npm resolves the package version available from the configured registry at execution time.
3. A compromised maintainer account, malicious release, registry compromise, or unexpected future update supplies altered package code.
4. `npx -y` downloads and executes that code without an installation confirmation.
5. The package runs with the invoking process's filesystem, environment, and network permissions.
6. Malicious code can access data available to that process or perform unauthorized local and network actions.

### Impact Assessment

A compromised dependency could execute arbitrary JavaScript under the invoking user's privileges. Potential i
...[truncated 552 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin the package to an exact reviewed version, such as spraay-x402-mcp@X.Y.Z.
  2. Record and verify package integrity through a lockfile and trusted registry metadata.
  3. Install the package separately and inspect it before execution instead of using immediate npx -y execution.
  4. Disable npm lifecycle scripts where feasible during installation.
  5. Publish reproducible build information, release hashes, and signed provenance.
  6. Run the MCP server in a restricted environment with minimal filesystem, environment-variable, and network access.
  7. Expose only the MCP tools required for the current task rather than all 183 tools.
  8. Document the package's permissions, external services, and data flows before recommending execution.
  9. Prefer a locally vendored and reviewed implementation when practical.
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 70)May include surrounding context.

md
) + `blockhash`. Sign each with the sender keypair, submit to any RPC. Helper: `scripts/sign-and-send.js`.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 76)May include surrounding context.

Example request

bash
curl -X POST https://gateway-solana.spraay.app/solana/batch-send-token \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: <base64 payment proof>" \
  -d '{

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The skill instructs users to run an unpinned package via npx, which fetches and executes whatever version is current at invocation time. If the package is compromised, maliciously updated, or affected by dependency-chain compromise, this can lead to arbitrary code execution on the user's machine.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · SKILL.md (reported line 130)May include surrounding context.

md
- Always run `/solana/quote` first for batches > 50 recipients and show the user the cost before building.
- Validate addresses are base58 Solana pubkeys before submitting; the gateway rejects invalid ones but a pre-check saves the call fee.
- Blockhash expiry: sign and submit promptly after building. If `lastValidBlockHeight` passes, rebuild (re-call the endpoint).
- Never ask the user for a private key to send to the gateway — it doesn't accept keys, only public keys. Signing happens locally.
- Devnet is available for dry runs; check `/health` for the active network.

See `reference.md` for full request/response schemas and error codes.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation describes batch token transfers and automatic ATA creation costs but does not clearly warn users that these actions spend real on-chain funds and may create new token accounts at the sender’s expense. In a skill designed for mass payouts, this omission increases the risk of users unintentionally authorizing costly transactions, especially when unsigned transactions are returned for local signing and may be trusted without careful review.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.