Back to skill

Security audit

sol-bsc-dev-monitor-skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed wallet monitor, but it needs Review because it ships a reusable billing API key and client-side charging logic for a payment service.

Install only after reviewing the billing design. The monitoring behavior does not require private keys or sign blockchain transactions, but the published payment credential should be rotated and moved server-side, billing should require explicit user consent, and logs/detections should be treated as sensitive operational data rather than freely shared debug output.

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

T09 · Insecure Skill Coding Practices

Error
Location
billing-final.js:7
Finding
Hard-Coded Billing API Credential Exposes the Skill's Billing Identity<![CDATA[ ## Vulnerability Details **File Location**: `billing-final.js:7-15`; duplicated in `billing.js:8-16` and `SKILL.md:7-11` **Vulnerability Type**: Hard-coded secret and reusable API credential **Risk Level**: High ### Vulnerable Code ```javascript const axios = require('axios'); // Billing API URL / 課金API URL / Ссылка на API биллинга const BILLING_API_URL = 'https://skillpay.me/api/v1/billing'; const API_KEY = 'sk_f072a786149bc07fc8730b4683dc00f3e050e72441922284ca803cdee2b994b5'; const SKILL_ID = '282279e4-5370-4b9e-b5e7-9e07f0b3dc5c'; // Headers / ヘッダー / Заголовки const headers = { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }; ``` The credential is subsequently transmitted in requests such as: ```javascript const resp = await fetch(`${BILLING_API_URL}/charge`, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: userId, skill_id: SKILL_ID, amount }) }); ``` The same credential is also published in the Skill metadata: ```yaml payment: provider: skillpay.me api_key: sk_f072a786149bc07fc8730b4683dc00f3e050e72441922284ca803cdee2b994b5 price: 0.005 currency: USDT billing_mode: per_call ``` ### Technical Analysis A reusable API credential is embedded in source code and plaintext package metadata. Anyone with access to the package can extract the credential without executing the Skill. The source then uses that credential as an `X-API-Key` when invoking balance, charge, and payment-link endpoints. Sending an authentication credential to the declared billing provider is necessary for the billing feature, but distributing a shared secret to every Skill recipient is not a least-privilege design. Client-side embedded credentials cannot remain confidential. The exact server-side permissions of the key cannot be established from the supplied files. However, the available client code demonstrates that the key is accepted by endpoin ...[truncated 1334 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Immediately revoke and rotate the exposed API key. 2. Remove the key from all source files, documentation, metadata, repository history, published archives, and examples. 3. Do not replace it with another static credential in client-distributed code. 4. Route privileged billing operations through a trusted backend that keeps the provider credential server-side. 5. Give clients short-lived, user-bound, narrowly scoped authorization tokens where direct client requests are unavoidable. 6. Restrict tokens by skill ID, user ID, permitted endpoint, maximum charge amount, expiration time, and replay-resistant request identifiers. 7. Enforce all authorization and amount validation on the billing server; never trust a client-supplied `user_id`, `skill_id`, or `amount` without verification. 8. Add rate limiting, anomaly detection, idempotency keys, and immutable billing audit logs. 9. Use a secret-scanning gate in CI and pre-commit tooling to prevent future credential publication. 10. Review billing logs for misuse of the disclosed key and notify affected parties if unauthorized activity is identified. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
billing.js:23
Finding
Broken Billing Module Exports an Undefined Function and Silently Overrides chargeUser<![CDATA[ ## Vulnerability Details **File Location**: `billing.js:23-75` and `billing.js:100-104` **Vulnerability Type**: Duplicate function declaration and undefined export causing module-load failure **Risk Level**: Medium ### Vulnerable Code The file declares `chargeUser` twice in the same scope. The second declaration replaces the first: ```javascript async function chargeUser(userId, amount = 0.005) { try { const resp = await fetch(`${BILLING_API_URL}/charge`, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: userId, skill_id: SKILL_ID, amount }) }); const data = await resp.json(); if (data.success) { return { ok: true, balance: data.balance }; } return { ok: false, balance: data.balance, payment_url: data.payment_url }; } catch (error) { console.error('Billing error:', error.message); return { ok: false, error: error.message }; } } async function chargeUser(userId, amount = 0.005) { try { const resp = await fetch(`${BILLING_API_URL}/charge`, { method: 'POST', headers: headers, body: JSON.stringify({ user_id: userId, skill_id: SKILL_ID, amount: amount }) }); const data = await resp.json(); return { ok: data.success, balance: data.balance, paymentUrl: data.payment_url }; } catch (error) { console.error('Charge error:', error.message); return { ok: false, balance: 0, error: error.message }; } } ``` The module then exports `checkBalance`, which is never declared anywhere in `billing.js`: ```javascript module.exports = { checkBalance, chargeUser, getPaymentLink }; ``` ### Technical Analysis JavaScript function declarations in the same scope may be overwritten by a later declaration with the same name. Cons ...[truncated 1620 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement a single, tested `checkBalance` function or remove it from the exports and documentation. 2. Delete the duplicate `chargeUser` declaration and retain one canonical implementation. 3. Define and document one consistent response schema, including a single property name such as `paymentUrl`. 4. Check `resp.ok` before parsing or trusting response data. 5. Validate billing response fields and handle malformed or non-JSON responses. 6. Add tests that import the module, invoke every export, and verify success, insufficient-balance, network-error, and malformed-response behavior. 7. Enable linting rules such as `no-redeclare`, `no-undef`, and duplicate declaration checks in CI. 8. Consolidate `billing.js` and `billing-final.js` to avoid divergent security and correctness behavior. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
index-sol-safe.js:69
Finding
Solana Monitor Attempts an Unbounded Historical Scan from Genesis<![CDATA[ ## Vulnerability Details **File Location**: `index-sol-safe.js:69-85` and `index-sol-safe.js:116-118` **Vulnerability Type**: Unbounded RPC workload and resource exhaustion **Risk Level**: Medium ### Vulnerable Code ```javascript let lastSlot = 0; let slotsScanned = 0; let detections = loadDetections(); const endTime = startTime + (monitorDuration * 1000); while (Date.now() < endTime) { try { const currentSlot = await connection.getSlot(); if (currentSlot > lastSlot) { for (let i = lastSlot + 1; i <= currentSlot; i++) { const block = await connection.getBlock(i); if (block && block.transactions && block.transactions.length > 0) { for (const tx of block.transactions) { const detected = await checkTransaction(tx, address, connection); ``` After the loop, the counter is also calculated after overwriting its reference value: ```javascript lastSlot = currentSlot; slotsScanned += currentSlot - lastSlot; ``` ### Technical Analysis `lastSlot` is initialized to zero instead of the current Solana slot or a bounded historical checkpoint. On the first monitoring iteration, the code loops from slot 1 through the current network slot and makes an RPC block request for every iteration. This is far beyond the minimum privileges and resources required for the declared real-time monitoring feature. It can consume substantial network bandwidth, runtime, memory, RPC quota, and remote-provider capacity. Because each request is awaited serially, the process may never reach current activity during a normal monitoring session. The code also sets `lastSlot = currentSlot` before updating `slotsScanned`, making the reported increment zero. This conceals the actual amount of attempted work from the output. ### Attack Path 1. A user or external caller starts Solana monitoring. 2. The monitor initializes `lastSlot` to `0`. 3. It queries the current slot, which is substantially greater than zero. 4. It b ...[truncated 1035 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Initialize monitoring from the current slot: ```javascript let lastSlot = await connection.getSlot(); ``` 2. If historical coverage is required, use an explicit and strictly bounded lookback window. 3. Prefer Solana subscriptions or signature queries scoped to the monitored public key rather than scanning every block. 4. Set a maximum number of slots and transactions processed per cycle. 5. Add exponential backoff, jitter, request timeouts, concurrency limits, and provider rate-limit handling. 6. Validate and cap `duration`, including rejecting negative, non-finite, and excessively large values. 7. Correct the counter before assigning the current slot: ```javascript slotsScanned += currentSlot - lastSlot; lastSlot = currentSlot; ``` 8. Add cancellation support and operational metrics for RPC requests, failed slots, skipped slots, and processing lag. 9. Add tests that confirm a new session never starts at slot zero unless explicitly requested by an authorized historical-analysis mode. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
index-sol-safe.js:176
Finding
Solana Token Metadata Lookup References an Out-of-Scope Connection<![CDATA[ ## Vulnerability Details **File Location**: `index-sol-safe.js:176-194` and `index-sol-safe.js:226-230` **Vulnerability Type**: Out-of-scope variable and silently degraded detection results **Risk Level**: Low ### Vulnerable Code The transaction checker calls the metadata function without passing its available connection: ```javascript if (!preToken && tokenAmount.uiTokenAmount && tokenAmount.uiTokenAmount.amount > 0) { // New token received by target address log(`💰 New token detected!`); const tokenInfo = await getTokenInfo(tokenAmount.mint); return { signature: tx.transaction.signature, from: targetAddress, to: account.address, tokenMint: tokenAmount.mint, tokenSymbol: tokenInfo.symbol, amount: tokenAmount.uiTokenAmount.amount, decimals: tokenAmount.uiTokenAmount.decimals || 9 }; } ``` The called function references `connection`, but no variable with that name exists in its lexical or module scope: ```javascript async function getTokenInfo(mintAddress) { try { const accountInfo = await connection.getAccountInfo(mintAddress); if (accountInfo && accountInfo.data) { const data = accountInfo.data; ``` The exception is caught and replaced with fallback values: ```javascript } catch (error) { log(`❌ Error getting token info: ${error.message}`); } return { name: 'Unknown', symbol: 'UNKNOWN', decimals: 9 }; ``` ### Technical Analysis The valid Solana connection is local to `monitorSOL` and is passed into `checkTransaction`, but it is not passed onward to `getTokenInfo`. Therefore, `getTokenInfo` raises a `ReferenceError` whenever it attempts to access `connection`. The broad catch block suppresses the failure and always returns fallback metadata. As a result, apparent successful detections can contain misleading token symbols and decimal values. Incorrect decimal metadata is particularly relevant to financial research because it may materially distort displayed token quantities. ### A ...[truncated 984 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass the existing connection explicitly: ```javascript const tokenInfo = await getTokenInfo(tokenAmount.mint, connection); async function getTokenInfo(mintAddress, connection) { const accountInfo = await connection.getAccountInfo( new PublicKey(mintAddress) ); } ``` 2. Validate mint addresses with `PublicKey` before making RPC requests. 3. Do not silently present fallback decimal values as authoritative. Mark metadata status explicitly when lookup fails. 4. Use supported Solana token and metadata parsers rather than manually inferring nonstandard name and symbol offsets from raw account bytes. 5. Distinguish transient RPC errors, invalid mint addresses, unsupported metadata, and parsing errors in logs and output. 6. Add unit tests for successful metadata retrieval, invalid addresses, missing metadata, and provider failures. 7. Consider omitting unsupported symbol information rather than returning a plausible but unverified value. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims a unified monitor role, but the documented behavior includes undeclared persistent local logging and detections storage. Undisclosed data storage increases privacy and integrity risk because monitored addresses, counterparties, and activity history may be retained on disk without permission or user awareness.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims a unified monitor role, but the documented behavior includes undeclared persistent local logging and detections storage. Undisclosed data storage increases privacy and integrity risk because monitored addresses, counterparties, and activity history may be retained on disk without permission or user awareness.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims a unified monitor role, but the documented behavior includes undeclared persistent local logging and detections storage. Undisclosed data storage increases privacy and integrity risk because monitored addresses, counterparties, and activity history may be retained on disk without permission or user awareness.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill claims a unified monitor role, but the documented behavior includes undeclared persistent local logging and detections storage. Undisclosed data storage increases privacy and integrity risk because monitored addresses, counterparties, and activity history may be retained on disk without permission or user awareness.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file embeds a full billing and charging workflow, including a hardcoded API key and functions to charge users and generate payment links, which materially exceeds the declared purpose of a 'wallet monitor' with 'manual buy only, no private keys'. This capability mismatch is dangerous because it can enable undisclosed monetization or unauthorized charging behavior under a misleading skill description, increasing phishing and fraud risk.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code has direct capability to charge users and create payment links even though those operations are unrelated to a monitoring-only wallet tool. In this context, unjustified payment functionality is dangerous because it broadens the attack surface from passive monitoring to active monetization, making deceptive billing or coercive paywalling possible.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file implements active billing and charging behavior even though the skill is described as a monitor-only wallet tool. This mismatch is dangerous because users and reviewers may trust the declared scope while the code silently performs billable external actions, creating unauthorized charges and undermining informed consent.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README says detections and logs are persisted, but it does not clearly warn that monitored wallet addresses, transaction hashes, and timing/activity data may be written to local files. On shared systems or poorly secured environments, this can leak sensitive operational intelligence about which wallets are being tracked and when noteworthy activity occurred.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The README presents the skill as a monitor-only blockchain tool with no wallet interactions, but later documents a billing/payment interface that is unrelated to passive monitoring. This mismatch increases the risk of deceptive scope expansion: users may run or integrate payment-related commands under the assumption the project is strictly observational, which can expose funds, credentials, or billing identifiers unexpectedly.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This is a real privacy and operational-security issue. The document repeatedly says logs can be safely shared, but the examples and described contents include wallet addresses, token addresses, transaction signatures/hashes, and timestamps, which are sensitive metadata that can deanonymize users, reveal trading behavior, or expose monitored targets even if they are public on-chain.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool scope or permissions despite documenting capabilities that require network access and likely local file writes. This weakens sandboxing and informed consent because the platform and user cannot clearly constrain what the skill is allowed to do.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The README presents a user-facing error message in Chinese only ("余额不足。最低充值...") within an otherwise English document. This imposes a language/locale on users without opt-in or an explicit statement that the skill is intended only for Chinese-speaking users.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The billing flow section uses Chinese-only labels and outcomes (for example, 用户请求监控, 是, No), and the SDK section continues this pattern. Because the skill does not state a Chinese-only locale or offer language choice, this is a natural-language locale policy issue.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The documentation says no wallet information is collected, yet the examples and storage paths show monitored addresses and transfer counterparties are recorded and persisted. This is a privacy and transparency issue because blockchain addresses are still user- or entity-linked data in context and may reveal trading or monitoring interests.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The skill states there are no wallet interactions, but it also documents automatic withdrawal to a user's wallet and integration with a payment platform. Misrepresenting financial interactions can mislead users about where funds-related operations occur and hide financially sensitive side effects.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code transmits user identifiers to an external billing service for charging and payment-link creation without any evidence of disclosure, consent, or minimization. In a wallet-monitoring skill, undisclosed third-party sharing is more concerning because users may not expect their identifiers to be sent to a billing provider at all.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
Core skill execution is placed behind a billing gate, as indicated by the 'Execute your skill' comment after a successful charge. This is risky because it contradicts the manifest framing and can mislead users into invoking a monitoring tool that silently attempts payment before performing its primary function.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code integrates an external billing API and embeds a live-looking API key in a wallet monitoring skill where such access is not justified by the advertised functionality. This expands the trust boundary, allows undisclosed transmission of user billing identifiers, and creates risk of abuse if the credential is extracted or reused.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The file hardcodes an API key and uses it for external billing calls without any disclosure or secure secret handling. Exposed credentials can be harvested from source, logs, or package distributions and then abused to make fraudulent billing requests or access the billing backend.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
A comment labels the routine as a balance check, but the function actually submits a charge request to the billing API. Misleading naming and comments can conceal monetization side effects from maintainers, auditors, or users, increasing the chance of accidental deployment of unauthorized charging behavior.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The billing requests send user identifiers, skill identifiers, and payment-related values to a third-party service without any visible user disclosure or consent mechanism in this file. In a monitor-only skill context, this is more suspicious because users would not reasonably expect their identifiers to be transmitted for billing operations.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The skill persists monitoring activity to local log and detection files, which creates a privacy and data-retention risk for wallet addresses and transaction history. In a wallet-monitoring context, users may reasonably expect transient observation rather than durable local storage, so undisclosed persistence can expose sensitive activity to other local users, backups, or later compromise.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The code writes wallet-related monitoring activity to local files without clear disclosure or consent, which creates a privacy risk. Because blockchain addresses can often be linked to individuals or trading behavior, retaining this data locally can leak sensitive financial patterns through file access, backups, or incident response artifacts.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
Using a third-party RPC endpoint for wallet monitoring exposes user interest and transaction correlation to an external service without explicit warning. Even if the address is not sent as a direct RPC parameter in every call, the monitored context and follow-on contract lookups can still reveal sensitive usage patterns and create a privacy dependency on the endpoint operator.

Description-Behavior Mismatch

Medium
Confidence
85% confidence
Finding
The manifest describes a read-only wallet monitor with manual buy only, yet the module imports `Keypair`, `SystemProgram`, `Transaction`, and `sendAndConfirmTransaction`, which are capabilities for constructing and submitting Solana transactions. Even though they are not used in this file, their presence is inconsistent with the stated monitor-only scope and no-private-keys positioning.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
index-sol-safe.js:9

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
billing-final.js:9

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
billing.js:10

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:9