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## 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
## 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## 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
## 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
Content
-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.**
Confidence
80% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

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.

Context-Inappropriate Capability

High
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.

Lp3

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.

Vague Triggers

Medium
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.

Natural-Language Policy Violations

Medium
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.

External Transmission

Medium
Category
Data Exfiltration
Content
# 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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
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"
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.

External Transmission

Medium
Category
Data Exfiltration
Content
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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
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.

Intent-Code Divergence

Medium
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.

Description-Behavior Mismatch

Medium
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.

Natural-Language Policy Violations

Medium
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.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib>=3.5.0
numpy>=1.20.0
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.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib>=3.5.0
numpy>=1.20.0
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.

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.

Missing User Warnings

Low
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.

Static analysis

No suspicious patterns detected.