Back to skill

Security audit

CryptoLens

Security checks for vulnerabilities and agentic risk

Overview

This paid crypto-analysis skill mostly does what it claims, but it needs Review because its billing implementation embeds a reusable API key and leaves charge handling insufficiently controlled.

Install only if you are comfortable with a paid skill sending your wallet-based billing identifier to SkillPay and token queries to external market-data services. Before production use, the publisher should rotate and remove the embedded billing key, make exact charges verifiable, secure temporary files, and pin dependencies.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/crypto_lens.py:32
Finding

Hardcoded SkillPay API Credential Exposed in Distributed Source Code

Content
View full analysis

Vulnerability Details

File Location: scripts/crypto_lens.py:32-34
Vulnerability Type: Hardcoded API credential
Risk Level: High

Vulnerable Code

python
BILLING_URL = "https://skillpay.me/api/v1/billing"
BILLING_API_KEY = "sk_fbda2cd31455722ee28f08aebbf77af5f0002f21d1832f1b2102b756e20f2981"
SKILL_ID = "73d7f580-817c-4df2-a0fb-0572f93e4b97"

The credential is subsequently transmitted as an authentication header:

python
data = _post_json(
    f"{BILLING_URL}/charge",
    {"user_id": user_id, "skill_id": SKILL_ID},
    headers={"X-API-Key": BILLING_API_KEY},
)

Technical Analysis

The Skill embeds a live-looking SkillPay API key directly in a client-side Python file. Any user who downloads, installs, or otherwise obtains the Skill package can extract and reuse this credential independently of the intended program.

Although SKILL.md claims that the key can only initiate charges and cannot withdraw funds, this restriction is enforced externally by SkillPay and cannot be verified from the audited source. A static credential distributed to every client also cannot reliably distinguish legitimate Skill requests from requests made by an attacker.

The billing request contains a caller-controlled user_id and a fixed skill_id. The request does not bind the API credential to a particular installation, invocation, command, or expected price. The actual price is controlled by the remote SkillPay configuration rather than included and validated by the client.

Attack Path

  1. An attacker downloads or reads the Skill package.
  2. The attacker extracts BILLING_API_KEY, SKILL_ID, and the billing endpoint from scripts/crypto_lens.py.
  3. The attacker constructs requests to https://skillpay.me/api/v1/billing/charge.
  4. The attacker supplies the exposed key in the X-API-Key header and submits chosen billing identifiers in the JSON request body.
  5. If the remote service do ...[truncated 1282 chars]
Remediation
View remediation

Remediation Suggestions

  1. Revoke and rotate the exposed API key because it must be treated as compromised once distributed.
  2. Remove long-lived billing credentials from all client-side source code and package history.
  3. Route billing through a publisher-controlled server that stores the credential in a secrets manager or protected environment variable.
  4. Issue short-lived, narrowly scoped invocation tokens instead of distributing a reusable publisher credential.
  5. Bind each authorized billing operation to the user identity, Skill ID, command, exact amount, expiration time, and a unique nonce.
  6. Require the client to display and validate the exact charge amount returned by the billing service before performing the paid operation.
  7. Add replay protection, per-user and per-key rate limits, anomaly detection, and auditable request identifiers.
  8. Avoid relying on documentation claims about key permissions; enforce least privilege through the billing provider's server-side policy.
  9. Establish an automated credential-rotation and incident-response process.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/crypto_lens.py:113
Finding

Predictable Files in Shared Temporary Directory Permit Symlink and Cache-Poisoning Attacks

Content
View full analysis

Vulnerability Details

File Location: scripts/crypto_lens.py:113-133, with additional affected paths at scripts/crypto_lens.py:688-690 and scripts/crypto_lens.py:1007-1009
Vulnerability Type: Unsafe temporary-file handling
Risk Level: Medium

Vulnerable Code

python
def _cache_path(prefix, key):
    safe = key.replace("/", "-").replace(" ", "_")
    return f"/tmp/cryptolens_{prefix}_{safe}.json"


def _read_cache(path, max_age=CACHE_TTL_SEC):
    try:
        if time.time() - os.stat(path).st_mtime > max_age:
            return None
        with open(path, "r") as f:
            return json.load(f)
    except (FileNotFoundError, OSError, json.JSONDecodeError):
        return None


def _write_cache(path, data):
    try:
        with open(path, "w") as f:
            json.dump(data, f)
    except OSError:
        pass

Predictable chart filenames are also generated in the shared /tmp directory:

python
ts = int(time.time())
chart_path = f"/tmp/cryptolens_compare_{ts}.png"
fig.subplots_adjust(left=0.06, right=0.94, top=0.94, bottom=0.08)
fig.savefig(chart_path, dpi=150)
python
ts = int(time.time())
chart_path = f"/tmp/cryptolens_chart_{symbol}_{ts}.png"
fig.subplots_adjust(left=0.08, right=0.92, top=0.95, bottom=0.06)
fig.savefig(chart_path, dpi=150)

Technical Analysis

Cache and chart files are stored directly in the globally shared /tmp directory using deterministic or readily predictable names. Cache files are derived from public token identifiers and fixed prefixes. Chart names use timestamps with one-second resolution and, for technical-analysis charts, a validated public symbol.

Cache writes use ordinary open(path, "w"), which follows symbolic links and does not request exclusive creation. Chart output is similarly passed to fig.savefig() without first securely creating a unique destination. No private per-user directory, ...[truncated 2929 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create a private temporary directory with tempfile.TemporaryDirectory() or tempfile.mkdtemp() and mode 0700.
  2. Generate files with tempfile.NamedTemporaryFile() or tempfile.mkstemp() rather than timestamp-based or deterministic names.
  3. For persistent caches, use a private user cache directory with verified ownership and permissions rather than /tmp.
  4. Use exclusive creation semantics and reject existing paths when generating new output.
  5. Do not follow symbolic links. Where direct low-level file creation is required, use appropriate platform protections such as O_NOFOLLOW, O_CREAT, and O_EXCL.
  6. Open cache files with restrictive permissions such as 0600, then pass the securely opened file object to the serializer.
  7. Validate cache ownership, file type, permissions, and integrity before reading it.
  8. Authenticate cached data with a keyed integrity mechanism if untrusted local users can access the cache namespace.
  9. Use cryptographically random chart filenames and return only paths created securely by the current invocation.
  10. Remove generated files after delivery or apply a controlled retention policy to reduce stale-file exposure.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (18)

YARA rule 'ransomware_behavior': Ransomware-like patterns (mass encryption, ransom notes) [malware]

Critical
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

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

md
-15
- Volume + price confirmation: ±8
- Weighted sum → normalized to 0-100

**Billing:** 1 token (0.001 USDT) per call.

## Duration Format

`30m`, `3h`, `12h`, `24h` (default), `2d`, `7d`, `14d`, `30d`

## Output Format

Returns JSON with:
- `text_plain` — Formatted text summary
- `chart_path` — Path to generated PNG chart

**Chart as image (always when chart_path is present):**
You must send the chart as a **photo**, not as text. In your reply, output `text_plain` and on a new line: `MEDIA: ` followed by the exact `chart_path` value (e.g. `MEDIA: /tmp/cryptolens_chart_BTC_1769204734.png`). Do **not** write `[chart: path]` or any other text placeholder — only the `MEDIA: <chart_path>` line makes the image appear.

## Billing

All commands cost 1 token (0.001 USDT) per call via SkillPay.me (BNB Chain USDT).
Billing credentials (API key and Skill ID) are embedded in the script — this is the standard SkillPay integration pattern for paid skills.

**`--user-id` is required.**

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This is a material trust and billing issue: the skill declares embedded billing credentials, omits clear declaration of external billing behavior in a safe permission model, and static analysis indicates a price mismatch where compare may charge 5 tokens despite documentation claiming 1. Any undisclosed or inconsistent charging behavior can cause unauthorized or deceptive billing outcomes, especially when combined with auto-handling of user billing identity.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill derives a persistent identifier from hostname, username, and home directory, creating a stable fingerprint tied to the execution environment. Even though it hashes the values, this still transmits derived host identity data to the billing service without explicit consent and can enable tracking or cross-session correlation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises execution of a Python script that clearly implies network access, local file output, and potentially environment-variable access, yet it declares no explicit tool/permission boundaries. That weakens sandboxing and review because consumers cannot easily tell what capabilities the skill will exercise, increasing the chance of overbroad execution or hidden side effects.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description says to use the skill when a user asks for crypto comparison, portfolio analysis, or 'should I buy/sell' questions, which are broad phrases that can occur in many general finance conversations. The file does not provide negative examples or tighter constraints distinguishing when this skill should or should not activate.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documented output includes fixed signal labels in Chinese only, which imposes a specific language on users regardless of their locale or preference. There is no opt-in, language selection, or justification that this skill is intended only for a Chinese-language audience.

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 · scripts/crypto_lens.py (reported line 27)May include surrounding context.

python
# Constants
# ---------------------------------------------------------------------------
CACHE_TTL_SEC = 300
COINGECKO_PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies={currency}"
COINGECKO_SEARCH_URL = "https://api.coingecko.com/api/v3/search?query={query}"
COINGECKO_MARKET_CHART_URL = "https://api.coingecko.com/api/v3/coins/{id}/market_chart?vs_currency={currency}&days={days}"
HYPERLIQUID_INFO_URL = "https://api.hyperliquid.xyz/info"

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 · scripts/crypto_lens.py (reported line 28)May include surrounding context.

python
# Constants
# ---------------------------------------------------------------------------
CACHE_TTL_SEC = 300
COINGECKO_PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies={currency}"
COINGECKO_SEARCH_URL = "https://api.coingecko.com/api/v3/search?query={query}"
COINGECKO_MARKET_CHART_URL = "https://api.coingecko.com/api/v3/coins/{id}/market_chart?vs_currency={currency}&days={days}"
HYPERLIQUID_INFO_URL = "https://api.hyperliquid.xyz/info"

External Transmission

Medium
Category
Data Exfiltration
Confidence
100% confidence
Finding

This line includes a hard-coded live-looking SkillPay API key directly in source code. Embedded secrets are highly dangerous because anyone with code access can reuse the credential to impersonate the skill, submit billing actions, or access billing-related data depending on API permissions.

Content

Scanner excerpt · scripts/crypto_lens.py (reported line 29)May include surrounding context.

python
CACHE_TTL_SEC = 300
COINGECKO_PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies={currency}"
COINGECKO_SEARCH_URL = "https://api.coingecko.com/api/v3/search?query={query}"
COINGECKO_MARKET_CHART_URL = "https://api.coingecko.com/api/v3/coins/{id}/market_chart?vs_currency={currency}&days={days}"
HYPERLIQUID_INFO_URL = "https://api.hyperliquid.xyz/info"

BILLING_URL = "https://skillpay.me/api/v1/billing"

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 · scripts/crypto_lens.py (reported line 30)May include surrounding context.

python
COINGECKO_PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids={ids}&vs_currencies={currency}"
COINGECKO_SEARCH_URL = "https://api.coingecko.com/api/v3/search?query={query}"
COINGECKO_MARKET_CHART_URL = "https://api.coingecko.com/api/v3/coins/{id}/market_chart?vs_currency={currency}&days={days}"
HYPERLIQUID_INFO_URL = "https://api.hyperliquid.xyz/info"

BILLING_URL = "https://skillpay.me/api/v1/billing"
BILLING_API_KEY = "sk_fbda2cd31455722ee28f08aebbf77af5f0002f21d1832f1b2102b756e20f2981"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code sends user_id and skill_id to the external SkillPay billing API, and _auto_user_id is designed to derive that identifier from local machine/user attributes. There is no visible prompt, print/log disclosure, or warning in this file informing the user that invoking the skill may transmit billing-related identity data to a third party.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code documents get_candles as returning OHLCV candles, and chart/analyze present candlestick-based technical analysis. However, in the CoinGecko path it synthesizes OHLC candles from simple price samples and sets volume to 0, which contradicts the stated meaning of 'OHLCV candles' and can materially change chart semantics.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest explicitly states '1 token (0.001 USDT) per call for all commands', but the code comments and behavior treat compare differently by labeling it 'compare = 5 tokens' while still calling the same billing endpoint. This is a user-facing intent mismatch because the skill claims uniform per-call pricing but the implementation/documentation indicate special pricing for one command.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill hardcodes Chinese natural-language labels such as 强烈看涨, 看涨, and related analysis text, and later emits full Chinese recommendations and signal descriptions. Because no language selection or opt-in is offered, this creates a language/locale policy violation for users expecting configurable or default-localized output.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified with only a lower bound, which allows future unreviewed versions of matplotlib to be installed. This weakens build reproducibility and can introduce supply-chain risk or breakages if a later release contains a vulnerability or incompatible behavior.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
matplotlib>=3.5.0
numpy>=1.20.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The numpy requirement is also unpinned, so installations may resolve to different versions over time, including releases with known defects or security advisories. This creates a preventable supply-chain and reproducibility weakness even if no exploit is directly present in this file.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
matplotlib>=3.5.0
numpy>=1.20.0

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +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
89% confidence
Finding

Because numpy is not pinned, it is impossible to verify whether the eventually installed version is affected by one of the known advisories. In a crypto-analysis skill, dependency integrity matters because compromise or instability in core numeric libraries could affect analysis correctness or expose the environment to package-level issues.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill sends user-provided token symbols to CoinGecko search and also makes additional external requests to CoinGecko and Hyperliquid for pricing and chart data. The code contains no user-visible warning, confirmation, or disclosure that running analysis causes outbound network calls carrying user query terms to third-party services.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.