Back to skill

Security audit

Crypto Short Signal Generator

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent paid crypto-signal purpose, but its payment and API implementation exposes a hardcoded financial API key and trusts caller-supplied billing identity.

Review before installing. The publisher should remove and rotate the embedded SkillPay key, require injected secrets, bind billing to authenticated platform identity, validate requests before any charge, pass the advertised price explicitly, add idempotency/duplicate-charge protections, disclose what user data is sent to SkillPay, and pin reviewed dependencies.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:12
Finding
Hardcoded SkillPay API Credential Exposed in Source and Configuration<![CDATA[ ## Vulnerability Details **File Location**: `index.js:12`, `api.js:12`, `config.json:15` **Vulnerability Type**: Hardcoded secret / plaintext API credential **Risk Level**: High ### Vulnerable Code `index.js:12` ```javascript const API_KEY = process.env.SKILLPAY_API_KEY || 'sk_0e14dceabeea3a6371770165736b89add613f7ab8f729c57aef555525b0f1a00'; ``` `api.js:12` ```javascript const API_KEY = process.env.SKILLPAY_API_KEY || 'sk_0e14dceabeea3a6371770165736b89add613f7ab8f729c57aef555525b0f1a00'; ``` `config.json:15` ```json "api_key": "sk_0e14dceabeea3a6371770165736b89add613f7ab8f729c57aef555525b0f1a00", ``` The credential is subsequently attached to outbound requests: ```javascript const headers = { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }; ``` ### Technical Analysis A live-format SkillPay API credential is embedded directly in two JavaScript files and the public configuration file. Supporting an environment variable does not protect the credential because the hardcoded value is automatically used whenever the environment variable is absent. Anyone who can download the package, inspect a deployment artifact, or access repository history can recover the credential without executing the skill. The same credential is used for billing requests and paid analysis requests, increasing the scope of exposure. Secret values committed to source control must be considered compromised even after they are removed from the latest revision because they may remain in package caches, published releases, forks, logs, and repository history. ### Attack Path 1. An attacker downloads or otherwise obtains the skill package. 2. The attacker opens `index.js`, `api.js`, or `config.json`. 3. The attacker extracts the plaintext SkillPay API key. 4. The attacker constructs requests containing the header: `X-API-Key: sk_0e14dceabeea3a6371770165736b89add613f7ab8f729c57aef555525b0f1a00`. 5. The attacker submits requests to the billing or paid- ...[truncated 705 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed credential immediately; deleting it from the current files is not sufficient. 2. Remove the key from `index.js`, `api.js`, `config.json`, published packages, deployment artifacts, and repository history. 3. Require `SKILLPAY_API_KEY` to be injected by an approved secret manager at deployment time. 4. Fail closed when the environment variable is absent instead of using a fallback credential: ```javascript const API_KEY = process.env.SKILLPAY_API_KEY; if (!API_KEY) { throw new Error('SKILLPAY_API_KEY is required'); } ``` 5. Do not include secret values in distributable configuration files. Configuration should describe only the environment-variable name. 6. Use separate, narrowly scoped credentials for billing and analysis so compromise of one service does not expose the other. 7. Apply key restrictions where supported, including endpoint scope, rate limits, source restrictions, expiration, and monitoring. 8. Review SkillPay access logs for unauthorized requests made with the exposed key. 9. Add automated secret scanning to CI and pre-commit checks to prevent recurrence. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.js:80
Finding
Caller-Controlled User Identifier Is Trusted for Billing and Paid API Access<![CDATA[ ## Vulnerability Details **File Location**: `index.js:27-31, 81`, `api.js:64-68, 134` **Vulnerability Type**: Missing identity binding / insecure direct object reference **Risk Level**: High ### Vulnerable Code `index.js:27-31` ```javascript const { data } = await axios.post(BILLING_URL + '/charge', { user_id: userId, skill_id: SKILL_ID, amount: amount, }, { headers }); ``` `index.js:80-82` ```javascript async function main(event) { const userId = event.user_id || event.userId || 'anonymous'; const inputData = event.input || event.data || {}; ``` `api.js:64-68` ```javascript const { data } = await axios.post(BILLING_URL + '/charge', { user_id: userId, skill_id: SKILL_ID, amount: amount, }, { headers }); ``` `api.js:133-135` ```javascript async function handleRequest(event) { const userId = event.user_id || event.userId || 'anonymous'; const inputData = event.input || event.data || {}; ``` The public layer also forwards the unverified identifier to the paid service: ```javascript const { data } = await axios.post(PAID_API_URL, { user_id: userId, token: tokenSymbol }, { headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' } }); ``` ### Technical Analysis The billed identity is read directly from caller-controlled event properties. The code does not verify a platform signature, authenticated session, token claim, or server-issued identity before forwarding the value to SkillPay under the skill's shared API credential. Consequently, the code does not establish that the caller owns the supplied `user_id`. If the billing or paid-service backend relies on the API key and submitted user identifier without an independent ownership check, the request can be attributed to an arbitrary account selected by the caller. The fallback to the shared identity `anonymous` creates an additional account-mixing risk because unrelated unauthenticated callers may be treated as ...[truncated 1268 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never derive a billing identity from caller-controlled request-body fields. 2. Obtain the user identifier exclusively from authenticated platform context, such as a verified session or cryptographically signed platform claim. 3. Validate token issuer, audience, signature, expiration, and nonce before accepting an identity. 4. Have the server derive the billing account from the authenticated principal rather than accepting an arbitrary `user_id`. 5. Require the billing backend to verify that the authenticated caller is authorized to act for the referenced account. 6. Reject unauthenticated requests instead of mapping all such requests to a shared `anonymous` account. 7. If identity must cross from the public layer to the paid layer, send a short-lived, audience-restricted signed assertion rather than an editable identifier. 8. Add tests that attempt to substitute another user's identifier and confirm that the request is rejected. 9. Log identity mismatches and repeated account-substitution attempts without logging credentials or sensitive authentication tokens. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:25
Finding
Broken Billing Workflow Uses a Zero Charge and Bills Before Input Validation<![CDATA[ ## Vulnerability Details **File Location**: `index.js:25-31, 86-103`, `api.js:62-68, 139-156` **Vulnerability Type**: Payment enforcement and transaction-ordering flaw **Risk Level**: Medium ### Vulnerable Code `index.js:25-31` ```javascript async function chargeUser(userId, amount = 0) { try { const { data } = await axios.post(BILLING_URL + '/charge', { user_id: userId, skill_id: SKILL_ID, amount: amount, }, { headers }); ``` `index.js:86-103` ```javascript // 第一步:扣费 const chargeResult = await chargeUser(userId); if (!chargeResult.ok) { // 余额不足,返回支付链接 return { status: "payment_required", payment_url: chargeResult.payment_url, message: chargeResult.message, skill_info: { name: "加密货币做空信号生成器", price: "0.001 USDT", description: "提前 7 天知道哪些币要暴跌 30%+", min_deposit: "8 USDT" } }; } // 第二步:验证输入 if (!tokenSymbol) { ``` `api.js:62-68` ```javascript async function chargeUser(userId, amount = 0) { try { const { data } = await axios.post(BILLING_URL + '/charge', { user_id: userId, skill_id: SKILL_ID, amount: amount, }, { headers }); ``` `api.js:139-156` ```javascript // 第一步:扣费 const chargeResult = await chargeUser(userId); if (!chargeResult.ok) { return { status: "payment_required", payment_url: chargeResult.payment_url, message: chargeResult.message }; } // 第二步:验证输入 if (!tokenSymbol) { return { status: "error", message: "请提供代币符号,如:ZRO, BARD, STABLE", examples: ["ZRO", "BARD", "STABLE"] }; } ``` ### Technical Analysis Both billing functions default `amount` to zero, and both callers invoke `chargeUser(userId)` without passing the advertised `0.001 USDT` price. The billing request therefore explicitly transmits `amount: 0`. Billing also occurs before checking whether a token was ...[truncated 2181 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define the price as a server-controlled constant and pass it explicitly: ```javascript const QUERY_PRICE = 0.001; const chargeResult = await chargeUser(authenticatedUserId, QUERY_PRICE); ``` 2. Reject zero, negative, nonnumeric, or caller-supplied amounts in `chargeUser`. 3. Validate and normalize the complete request before initiating any billing operation. 4. Ensure exactly one trusted layer owns charging. The other layer should verify a payment receipt rather than issue another charge. 5. Generate a unique idempotency key for each logical purchase and require the billing backend to enforce it. 6. Bind the payment receipt to the authenticated user, skill ID, requested operation, amount, and expiration time. 7. If analysis fails after payment, implement an explicit refund or retry policy. 8. Add automated tests for valid requests, missing tokens, unsupported tokens, retries, concurrent duplicates, paid-layer failures, and billing timeouts. 9. Reconcile the implementation with the advertised `0.001 USDT` price and monitor for successful zero-value transactions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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 (15)

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The file hardcodes a live-looking API key fallback and exposes billing and core analysis logic despite comments claiming these are private and not public. If this code is distributed with the skill, attackers can recover the secret, abuse the billing API, and replicate or tamper with the supposedly protected backend behavior.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The manifest states that the SkillPay API key should be supplied via environment variables, yet a live-looking secret is embedded directly in the configuration. Hardcoded secrets are easily leaked through source distribution, logs, or package reuse, allowing unauthorized parties to use the payment integration, impersonate the skill, or incur fraudulent charges.

Ssd 3

High
Confidence
99% confidence
Finding
A hardcoded payment API key is present in the skill configuration, which exposes a credential tied to financial operations. Because this is a crypto/payment-oriented skill, misuse of the leaked key could directly affect billing flows, generate fraudulent payment requests, or enable unauthorized API consumption, making the context more dangerous than an ordinary non-financial integration.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
This README presents the skill name, usage instructions, pricing, outputs, and warnings entirely in Chinese. That effectively forces a specific language for all users without offering a language/locale choice or documenting that the skill is intended only for a Chinese-language audience.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code sends the user's identifier and skill identifier to an external billing endpoint via HTTP, which is a network transmission of user/system data. Although comments describe billing internally, there is no visible confirmation prompt, log, or user-facing disclosure warning that this transmission occurs.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The manifest presents the skill name, description, category, tags, examples, and disclaimer entirely in Chinese, with no indication that users can choose another language or locale. This is a natural-language policy concern because the skill appears to enforce a single language experience without explicit user opt-in or documented regional limitation.

External Transmission

Medium
Category
Data Exfiltration
Content
const SKILL_ID = process.env.SKILL_ID || 'crypto-short-signal';

// 付费层 API 地址 (可以部署在 SkillPay Cloud 或你的服务器)
const PAID_API_URL = process.env.PAID_API_URL || 'https://api.skillpay.me/skills/crypto-short-signal/analyze';

const headers = { 
    'X-API-Key': API_KEY,
Confidence
97% confidence
Finding
The code sends user identifiers and requested token symbols to an external paid API, and separately sends billing data to a third-party billing service. In this context, the risk is elevated because a hardcoded fallback API key is present, making unauthorized use of those external endpoints more feasible if the source is exposed, and because data is transmitted off-platform without any visible minimization or consent controls.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill charges the user before validating input and without any explicit confirmation or visible pre-charge warning in this code path. In an agent setting, this can lead to unintended charges, especially when malformed or empty input is submitted, and can be abused through repeated invocations that debit balances without delivering useful service.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The example output sets `risk_level` to the Chinese value `高` inside an otherwise English-language skill description and response schema. This suggests the skill may force a specific language or locale in outputs without user opt-in or documented language selection.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
Natural-language strings and comments indicate the skill is oriented to Chinese only, and all user-facing messages returned by the API are in Chinese. There is no indication that the user can choose language or that the locale restriction is explicitly documented as an intentional regional constraint.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
User-facing messages and descriptions in this file are written in Chinese, and there is no indication that users can choose another language or that the skill is intentionally limited to Chinese-speaking users. That can violate language/locale policy when a specific language is imposed without opt-in or justification.

Intent-Code Divergence

Low
Confidence
78% confidence
Finding
The module header at L4-L6 says the public layer 'only contains billing interfaces and basic validation' and that core logic is elsewhere. However, the code also returns product metadata and strong marketing claims such as '提前 7 天知道哪些币要暴跌 30%+' in normal execution, which goes beyond the stated limited role of just billing/validation.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The package description is written entirely in Chinese, which indicates a fixed language choice in the skill's user-facing metadata. There is no accompanying opt-in, alternative locale, or justification that this skill is intended only for a Chinese-speaking or region-specific audience.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "Denny Huang",
  "license": "MIT",
  "dependencies": {
    "axios": "^1.13.6"
  },
  "engines": {
    "node": ">=18.0.0"
Confidence
88% confidence
Finding
The dependency uses a caret range (^1.13.6), which allows future minor/patch updates to be installed without review. In a security-sensitive skill, this weakens supply-chain integrity and can unexpectedly introduce vulnerable or malicious dependency versions during install or deployment.

Unverifiable Dependency: axios has 16 known advisory(ies) (CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding
The manifest declares axios without an exact pinned version, while known advisories exist for some axios releases. Because the actual installed version is not fixed or evidenced by a lockfile here, consumers may resolve to an affected release, creating risk such as SSRF, credential leakage, or request/response manipulation depending on how the library is used elsewhere in the skill.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
api.js:12

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
index.js:13