Back to skill

Security audit

xstocks-beta

Security checks for vulnerabilities and agentic risk

Overview

The skill is transparent about xStock lookup and trading, but its instructions can treat an amount or a simple yes as permission to sign and broadcast a financial swap.

Review this skill carefully before installing in an agent that has wallet access. It is reasonable for lookup-only use, but for trading you should require an explicit final confirmation of the exact swap details before any signing or broadcast, and avoid relying on partial mint-address lookups.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:60
Finding
Ambiguous User Input Can Be Treated as Authorization for a Financial Transaction## Vulnerability Details **File Location**: `SKILL.md:60-75` **Vulnerability Type**: Insufficient transaction authorization and unsafe agent instructions **Risk Level**: High ### Vulnerable Code Snippet ```markdown **IMPORTANT: Once the user confirms an amount, execute the entire buy flow immediately in one pass. Do NOT stop after confirming — proceed straight through steps 1–5 without waiting for further user input.** 1. **Resolve the mint** — run `scripts/search.py --filter "TOKEN" --address-only` to get the Solana address. 2. **Confirm with the user** — show amount, token name, and mint address. Ask the user to confirm. 3. **Once confirmed, execute immediately without pausing:** - **Build the swap** — use the **standard Jupiter quote + swap flow** (`jupiter_swap` tool, or `/quote` + `/swap` REST endpoints). **Do NOT use Jupiter Ultra** (`/ultra/...` endpoints) — Ultra transactions are not compatible with external signers. - **Sign and broadcast** — use your wallet tools (we recommend lobster.cash). If no wallet tool is configured, return the mint address so the user can execute with their own wallet. 4. **Report outcome** — only claim success when transaction status is `success` or `completed`. Share transaction ID and explorer link. ``` The later guidance broadens the definition of confirmation: ```markdown - **Do not pause between confirmation and execution.** When the user says "yes" or provides an amount, execute the swap immediately. Never reply with "confirmed" and then wait for another prompt. ``` ### Technical Analysis The skill instructs the agent to build, sign, and broadcast a swap as soon as the user provides an amount. Supplying an amount is not necessarily explicit authorization to execute a transaction; it may instead be part of a request for a quote, fee estimate, price comparison, or general discussion. The instructions are internally inconsistent. The numbered workflow requires the agent ...[truncated 2313 chars]
Remediation
## Remediation Suggestions Implement a strict two-stage quote and authorization workflow: 1. Treat an amount only as a transaction parameter, never as approval. 2. Resolve the asset and obtain a quote without signing or broadcasting. 3. Present the complete final transaction summary, including: - Input token and exact input amount. - Output token name, symbol, and full mint address. - Expected and minimum output amounts. - Slippage tolerance and price impact. - Network and provider fees. - Wallet address and Solana network. - Quote expiration or freshness information. 4. Require an explicit confirmation that unambiguously refers to the displayed transaction, such as “Confirm this swap.” 5. Reject generic responses such as an isolated amount or ambiguous “yes” if no current transaction summary is awaiting approval. 6. Bind confirmation to an immutable quote or transaction digest. If any material field changes, obtain confirmation again. 7. Keep quote retrieval separate from signing and broadcasting. 8. Add wallet-side transaction simulation and policy checks before signing. 9. Replace the unsafe instruction with language such as: ```markdown Providing an amount is not authorization to transact. Obtain a quote, display all material transaction details, and require explicit confirmation of that exact transaction before invoking any signing or broadcast tool. ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/xstocks/tokens.py:37
Finding
Substring-Based Mint Lookup Can Resolve an Unintended Token## Vulnerability Details **File Location**: `scripts/xstocks/tokens.py:37-43` **Vulnerability Type**: Improper input validation and ambiguous identifier matching **Risk Level**: Medium ### Vulnerable Code Snippet ```python def find_token_by_solana_address( tokens: List[Dict[str, Any]], address: str ) -> Dict[str, Any]: """Return the first token whose address matches. Returns {} if no match.""" if not address: return {} for t in tokens: if address in str(t.get("address", "")): return t return {} ``` ### Technical Analysis The reverse-lookup function uses the containment operator: ```python if address in str(t.get("address", "")): ``` This does not verify that the supplied address is the complete mint address. Any substring contained in a catalog address is accepted, and the first matching catalog entry is returned. The function also performs no validation of the `svm:` prefix, base58 encoding, address length, or uniqueness of the match. Solana mint addresses are security-sensitive identifiers and must be matched using exact normalized equality. First-match substring behavior creates ambiguity and makes the returned result dependent on catalog ordering. The command-line interface exposes this behavior through `--lookup`. It subsequently presents the returned entry as a matching token without warning that the input may only be a partial address. ### Attack Path 1. An attacker, user, or upstream component supplies a short partial value to `--lookup`, such as a fragment shared by one or more catalog addresses. 2. `find_token_by_solana_address` checks whether that fragment occurs anywhere in each stored address. 3. The function returns the first matching catalog entry rather than rejecting the incomplete identifier. 4. The command-line interface displays that entry as the resolved xStock. 5. A user or downstream agent relies on the incorrect result whe ...[truncated 990 chars]
Remediation
## Remediation Suggestions Replace substring matching with normalized, exact comparison: ```python def normalize_solana_address(address: str) -> str: value = address.strip() if value.startswith("svm:"): value = value[4:] return value def find_token_by_solana_address( tokens: List[Dict[str, Any]], address: str ) -> Dict[str, Any]: if not address or not address.strip(): return {} expected = normalize_solana_address(address) for token in tokens: candidate = normalize_solana_address(str(token.get("address", ""))) if candidate == expected: return token return {} ``` Additional hardening should include: 1. Validate that the normalized value is a complete, valid Solana public key. 2. Reject short prefixes and partial addresses with a clear error. 3. Treat the `svm:` prefix as optional only through explicit normalization. 4. Verify that catalog mint addresses are unique during development or startup. 5. Add tests for exact prefixed and unprefixed addresses, partial strings, whitespace, invalid base58 values, and ambiguous fragments. 6. Require downstream transaction flows to display and explicitly confirm the full normalized mint address.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger text is broad enough to activate on generic investing or stock-related requests, not just explicit xStocks intents. In an agent environment with wallet or trading capabilities, unintended invocation can steer users into a transactional flow they did not request, increasing the chance of mistaken asset identification or accidental trade preparation.

External Transmission

Medium
Category
Data Exfiltration
Content
from typing import Any, Dict, List


# Scraped from https://api.xstocks.fi/api/v1/token
# 104 tokens with Solana deployments
SOLANA_TOKENS: List[Dict[str, Any]] = [
    {"name": "Abbott xStock", "symbol": "ABTx", "address": "svm:XsHtf5RpxsQ7jeJ9ivNewouZKJHbPxhPoEy6yYvULr7"},
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
from typing import Any, Dict, List


# Scraped from https://api.xstocks.fi/api/v1/token
# 104 tokens with Solana deployments
SOLANA_TOKENS: List[Dict[str, Any]] = [
    {"name": "Abbott xStock", "symbol": "ABTx", "address": "svm:XsHtf5RpxsQ7jeJ9ivNewouZKJHbPxhPoEy6yYvULr7"},
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.