Back to skill

Security audit

Senddy

Security checks for vulnerabilities and agentic risk

Overview

This wallet skill is purpose-aligned, but it should be reviewed because its examples expose live fund-moving controls and wallet secrets without adequate safeguards.

Review carefully before installing or copying these examples. Use only with small test amounts until you add authentication, confirmations, limits, pinned dependencies, and real secret storage. Do not expose the daemon beyond a tightly controlled local channel, and treat the seed like a private key.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:252
Finding

Unauthenticated Wallet Daemon Permits Unauthorized Transfers and Withdrawals

Content
View full analysis
{ if (req.method !== 'POST') { res.writeHead(405); res.end(); return; } const chunks: Buffer[] = []; for await (const chunk of req) chunks.push(chunk as Buffer); const { method, params } = JSON.parse(Buffer.concat(chunks).toString()); try { let result: any; switch (method) { case 'getBalance': result = await agent.getBalance(); result = { ...result, shares: result.shares.toString(), estimatedUSDC: result.estimatedUSDC.toString() }; break; case 'getAddress': result = { address: agent.getReceiveAddress() }; break; case 'transfer': result = await agent.transfer(params.to, toUSDC(params.amount), params.opts); result = { ...result, shares: result.shares.toString() }; break; case 'withdraw': result = await agent.withdraw(params.to, toUSDC(params.amount)); result = { ...result, shares: result.shares.toString() }; break; ``` Equivalent vulnerable dispatch in `examples.md:37-51`: ```typescript const server = createServer(async (req, res) => { if (req.method !== 'POST') { res.writeHead(405); res.end(); return; } const chunks: Buffer[] = []; for await (const chunk of req) chunks.push(chunk as Buffer); const { method, params } = JSON.parse(Buffer.concat(chunks).toString()); try { let result: any; switch (method) { case 'getBalance': result = await agent.getBalance(); break; case 'getAddress': result = { address: agent.getReceiveAddress() }; break; case 'transfer': result = await agent.transfer(params.to, toUSDC(params.amount), params.opts); break; case 'w ...[truncated 2343 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:255
Finding

Unbounded HTTP Request Buffering Enables Denial of Service

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
examples.md:305
Finding

Wallet Seed Storage Helper Misrepresents Plaintext Hex as an Encrypted File

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding

Unpinned Package Installation and Dynamic npx Execution Create Supply-Chain Exposure

Content
View full analysis
Remediation
View remediation
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The quick-start section includes immediate transfer and withdraw calls, which can move funds and, in the withdrawal case, send USDC to a public address. While the document explains functionality, it does not clearly warn users before these examples that these are real asset-moving, potentially irreversible actions and that withdrawal exits the privacy pool.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The example daemon exposes sensitive wallet operations including transfer and withdraw over HTTP with no authentication, authorization, request validation, or anti-CSRF-style protections. Even though it binds to 127.0.0.1, any local process, malicious browser-assisted local request, compromised user session, or SSRF-capable application on the host may be able to trigger fund-moving actions and drain the wallet.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

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 316)May include surrounding context.

Then query it instantly from any client:

bash
# Check balance (use the port printed at startup)
curl -s -X POST http://127.0.0.1:18790 \
  -d '{"method":"getBalance"}' | jq

# Transfer

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 320)May include surrounding context.

Then query it instantly from any client:

bash
# Check balance (use the port printed at startup)
curl -s -X POST http://127.0.0.1:18790 \
  -d '{"method":"getBalance"}' | jq

# Transfer

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The example starts code via npx tsx, which resolves and executes packages that may not be version-pinned. That creates a supply-chain risk: users may run an unexpected or malicious package version, especially in automation or CI environments where examples are copied verbatim.

Content

No source excerpt is available for this finding.

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 · examples.md (reported line 82)May include surrounding context.

Query it from any script or agent (instant responses — use the port from stdout):

bash
curl -s -X POST http://127.0.0.1:18790 -d '{"method":"getBalance"}' | jq
curl -s -X POST http://127.0.0.1:18790 -d '{"method":"transfer","params":{"to":"senddy1...","amount":"5.00"}}' | jq

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 · examples.md (reported line 83)May include surrounding context.

Query it from any script or agent (instant responses — use the port from stdout):

bash
curl -s -X POST http://127.0.0.1:18790 -d '{"method":"getBalance"}' | jq
curl -s -X POST http://127.0.0.1:18790 -d '{"method":"transfer","params":{"to":"senddy1...","amount":"5.00"}}' | jq

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The examples show live transfer and withdraw operations against what appears to be real infrastructure without an explicit warning that these move real funds and may be irreversible. In a payments skill, copy-paste execution is likely, so omission of safety guidance increases the chance of accidental loss or unintended transfers.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The comment says the seed is saved to an encrypted file, but the code writes plaintext hex to disk with restrictive permissions only. This is dangerous because the seed is effectively the wallet secret; anyone who obtains local file access, backups, logs, or disk snapshots can take full control of funds.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The seed-management section handles highly sensitive credential material but does not give a strong, immediate warning commensurate with the risk. Because the seed controls private stablecoin wallets, normalizing writing it to disk without emphatic safety constraints can lead to credential theft and total wallet compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file describes a required 32-byte secret seed, developer API key, and methods for transfers and withdrawals in headless use, but it does not include any user-facing warning about safeguarding credentials or the irreversible nature of on-chain submissions. For markdown files, SQP-2 applies when the description omits warnings about behaviors that could affect user data, privacy, or system integrity.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.