Back to skill

Security audit

crypto-trader

Security checks for vulnerabilities and agentic risk

Overview

This crypto trading skill is mostly coherent, but it needs review because real-money trading safeguards are not reliably enforced in code.

Only install after reviewing the trading safeguards. Use paper/testnet mode, trade-only API keys with no withdrawal permission, IP allowlists where available, tightly controlled notification webhooks, and small limits. Do not enable live trading until the skill has a real live-mode authorization gate, corrected market-order valuation, reliable fill/loss accounting, and safer PID/state-file handling.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/risk_manager.py:145
Finding

Market Orders Bypass Monetary Risk Limits When Price Is Missing

Content
View full analysis
max_order: raise RiskLimitExceeded( "max_order_size", f"Order cost {estimated_cost:.2f} EUR exceeds max " f"{max_order:.2f} EUR for strategy '{strategy}'." ) max_open = self._get_limit(strategy, "max_open_orders") if max_open and open_order_count >= max_open: raise RiskLimitExceeded( "max_open_orders", f"Already {open_order_count} open orders (max {max_open}) " f"for strategy '{strategy}'." ) if side == "buy" and portfolio_value_eur > 0: max_pos_pct = self._get_limit(strategy, "max_position_size_pct") if max_pos_pct: pos_pct = (estimated_cost / portfolio_value_eur) * 100 if pos_pct > max_pos_pct: raise RiskLimitExceeded( "max_position_size", f"Position would be {pos_pct:.1f}% of portfolio " f"(max {max_pos_pct:.1f}%)." ) ``` ```python # scripts/strategies/dca.py amount = self.amount_per_buy / current_price return [{ "symbol": self.symbol, "side": "buy", "amount": round(amount, 8), "price": None, "order_type": "market", "exchange": self.exchange, "reason": ( f"DCA buy #{self.buy_count + 1}: {self.amount_per_buy:.2f} USDT " f"of {self.symbol} at {current_price:.2f} " f"(avg: {self.avg_price:.2f}, total: {self.total_invested:.2f} USDT)" ), }] ``` ### Technical Analysis The risk manager treats an absent market-order price as zero. Consequently, every market order with `price ...[truncated 1624 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:173
Finding

Documented Live-Trading Confirmation Requirement Is Not Enforced

Content
View full analysis
None: """Start a trading strategy.""" params = {} if params_json: try: params = json.loads(params_json) except json.JSONDecodeError as exc: _error(f"Invalid JSON params: {exc}") result = engine.start_strategy(strategy, params) _output(result) ``` ```python # scripts/strategy_engine.py strategy = strategy_class( strategy_id=strategy_id, params=merged_params, exchange_manager=self.exchange_manager, risk_manager=self.risk_manager, ) strategy.on_start() self._strategies[strategy_id] = strategy self._save_state() return { "status": "ok", "strategy_id": strategy_id, "strategy_name": strategy_name, "params": merged_params, "message": f"Strategy '{strategy_name}' started with ID {strategy_id}.", } ``` ```python # scripts/monitor_daemon.py risk_manager.validate_order( strategy=strategy_name, exchange=exchange, symbol=symbol, side=side, amount=amount, price=price, portfolio_value_eur=total_value, open_order_count=len(open_orders), ) order_type = signal_data.get("order_type", "market") order = exchange_manager.place_order( exchange, symbol, side, amount, price, order_type, ) ``` ### Technical Analysis `SKILL.md` requires explicit user confirmation before starting a strategy and before executing live trades. It also requires the user to be clearly warned when real money is involved. These requirements exist only as natural-language instructions. Neither the CLI, the strategy engine, nor the order-execution path ...[truncated 1533 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/monitor_daemon.py:346
Finding

Executed Trades Are Not Connected to Daily Loss and Strategy Fill Accounting

Content
View full analysis
None: """Record a completed trade for daily P&L tracking.""" with self._lock: self._reset_daily_if_needed() pnl = trade_info.get("realized_pnl_eur", 0) self._state["daily_pnl_eur"] = self._state.get("daily_pnl_eur", 0) + pnl self._state["trades_today"].append({ "timestamp": datetime.now(timezone.utc).isoformat(), "symbol": trade_info.get("symbol"), "side": trade_info.get("side"), "amount": trade_info.get("amount"), "price": trade_info.get("price"), "pnl_eur": pnl, }) self._save_state() ``` ```python # scripts/monitor_daemon.py order_type = signal_data.get("order_type", "market") order = exchange_manager.place_order( exchange, symbol, side, amount, price, order_type, ) logger.info( "Signal executed: %s %s %s %.8f on %s (strategy: %s)", order_type, side, symbol, amount, exchange, strategy_name, ) if notifier: notifier.send_alert("trade_executed", { "strategy": strategy_name, "symbol": symbol, "side": side, "amount": amount, "price": price or order.get("price"), "exchange": exchange, "reason": signal_data.get("reason", ""), }) ``` ### Technical Analysis The risk manager contains a `record_trade()` method that updates daily realized profit and loss. Repository-wide usage found no production call to this method after order placement or fill reconciliation; it is referenced only by its definition and tests. The execution path submits an order and sends a notification, but does not record a realized result. It also do ...[truncated 1541 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Open-Ended Dependency Versions Create Supply-Chain and Reproducibility Risk

Content
View full analysis
=4.5.37 pandas>=2.2.0 pandas-ta>=0.4.71b0 numpy>=1.26.0 pyyaml>=6.0.1 python-dotenv>=1.0.1 apscheduler>=3.10.4 requests>=2.31.0 aiohttp>=3.9.0 websockets>=12.0 python-telegram-bot>=21.0 discord.py>=2.3.2 tweepy>=4.14.0 praw>=7.7.1 vaderSentiment>=3.3.2 transformers>=4.40.0 torch>=2.2.0 feedparser>=6.0.11 beautifulsoup4>=4.12.3 sqlite-utils>=3.36 ``` The documented installation instruction is: ```bash pip install -r {baseDir}/requirements.txt ``` ### Technical Analysis Every dependency uses an open-ended minimum version. There is no lock file, upper bound, package hash, or reviewed artifact manifest. A future installation may therefore resolve versions that were never tested or audited with the Skill. This is especially consequential because the process imports network-capable and high-complexity packages while holding exchange API keys, notification credentials, and social-media API credentials. No typosquatted or demonstrably malicious package was identified in the reviewed list. The finding concerns the unsafe resolution policy and lack of build integrity controls, not proof that a listed dependency is currently malicious. ### Attack Path 1. A dependency or transitive dependency publishes a compromised, malicious, or incompatible release satisfying the lower-bound constraint. 2. The user follows the documented `pip install -r requirements.txt` instruction. 3. The package resolver selects the newer release. 4. Package installation or later import executes code with the Skill process's operating-system and environment privileges. 5. That code can access environment variables, local Skill state, and network resources available to the process. ### Impact Assessment A compromised dependency could obtain the same privileges as the Skill process, including ...[truncated 383 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/monitor_daemon.py:73
Finding

Unverified PID File Can Terminate an Unrelated Process

Content
View full analysis
None: _PID_PATH.parent.mkdir(parents=True, exist_ok=True) with open(_PID_PATH, "w") as fh: fh.write(str(os.getpid())) @staticmethod def _read_pid() -> Optional[int]: if _PID_PATH.exists(): try: return int(_PID_PATH.read_text().strip()) except (ValueError, OSError): pass return None @staticmethod def _is_process_running(pid: int) -> bool: try: os.kill(pid, 0) return True except (OSError, ProcessLookupError): return False ``` ```python def start(self) -> Dict[str, Any]: """Start the monitoring daemon.""" existing_pid = self._read_pid() if existing_pid and self._is_process_running(existing_pid): return { "status": "already_running", "pid": existing_pid, "message": "Monitor daemon is already running.", } self._running = True self._state["running"] = True self._state["started_at"] = datetime.now(timezone.utc).isoformat() self._write_pid() self._save_state() return { "status": "started", "pid": os.getpid(), "message": "Monitor daemon started.", } ``` ```python def stop(self) -> Dict[str, Any]: """Stop the monitoring daemon.""" pid = self._read_pid() if pid and self._is_process_running(pid): try: os.kill(pid, signal.SIGTERM) self._remove_pid() self._state["running"] = False self._save_state() return { "status": "stopped", "pid": pid, "message": "Monitor daemon stopped.", } ``` ### Technical Analysis `start()` writes the P ...[truncated 1603 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (78)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

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

Content

Scanner excerpt · scripts/notifier.py (reported line 188)May include surrounding context.

python
for key, value in data.items():
                lines.append(f"{key}: {value}")

        return "\n".join(lines)

    # ------------------------------------------------------------------
    # Telegram
    # ------------------------------------------------------------------

    def _send_telegram(self, message: str) -> bool:
        """Send a message via Telegram bot."""
        bot_token = os.environ.get("TELEGRAM_BOT_TOKEN", "")
        chat_id = os.environ.get("TELEGRAM_CHAT_ID", "")

        if not bot_token or not chat_id:
            logger.warning("Telegram credentials not configured.")
            return False

        try:
            import requests
            url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
            payload = {
                "chat_id": chat_id,
                "text": message,
                "parse_mode": "HTML",
            }
            resp = requests.post(url, json=payload, timeout=10)
            if resp.status_code == 200:

Tainted flow: 'url' from os.environ.get (line 197, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/notifier.py (reported line 203)May include surrounding context.

python
"text": message,
                "parse_mode": "HTML",
            }
            resp = requests.post(url, json=payload, timeout=10)
            if resp.status_code == 200:
                return True
            logger.error("Telegram API error: %d %s", resp.status_code, resp.text)

Tainted flow: 'webhook_url' from os.environ.get (line 218, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The Discord webhook URL is taken directly from an environment variable and used as the full outbound destination. If an attacker can influence environment configuration, alerts containing trading activity, balances, errors, or other operational data can be silently redirected to an attacker-controlled endpoint.

Content

Scanner excerpt · scripts/notifier.py (reported line 227)May include surrounding context.

python
try:
            import requests
            payload = {"content": message}
            resp = requests.post(webhook_url, json=payload, timeout=10)
            if resp.status_code in (200, 204):
                return True
            logger.error("Discord webhook error: %d %s", resp.status_code, resp.text)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant includes undeclared local persistence of strategy state, which is security-relevant because storing operational or account data on disk without declaring it affects confidentiality and user expectations. In a financial trading context, hidden persistence can expose portfolio metadata, strategy details, or operational state to other local processes or users.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.py (reported line 34)May include surrounding context.

python
_SCRIPTS_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(_SCRIPTS_DIR))

_env_path = _SCRIPTS_DIR.parent.parent.parent / ".env"
if _env_path.exists():
    try:
        from dotenv import load_dotenv

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code automatically converts strategy signals into live exchange orders with no interactive confirmation, execution guard, or enforced paper-trading mode at the point of execution. In a crypto-trading skill, this is especially dangerous because bad strategy output, compromised upstream components, or accidental activation can immediately trigger real financial loss across connected exchanges.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/notifier.py (reported line 117)May include surrounding context.

python
"""Find the alert rule matching the given type."""
        for rule in self._alert_rules:
            if rule.get("type") == alert_type:
                return rule
        return None

    # ------------------------------------------------------------------

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill declares access to API keys and describes capabilities requiring network, local file persistence, and file reads/writes, but it does not declare any explicit tool scope or permissions boundaries. In a trading skill, undeclared capabilities are especially dangerous because they can place orders, read sensitive credentials, persist state, and send outbound notifications without clear least-privilege constraints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The invocation guidance is broad enough to trigger the skill for general portfolio management or market-analysis questions, potentially invoking a high-risk trading-capable skill when the user only wanted information. In a financial context, over-broad routing materially increases the chance of exposing balances, reading credentials, or leading the user into accidental trade workflows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill describes a background daemon that continuously checks orders, evaluates signals, runs sentiment analysis, and sends alerts to external channels, but it does not require explicit user warning or consent for ongoing background activity and outbound notifications. In a trading skill, silent continuous execution can create privacy leakage, unexpected network activity, operational risk, and confusion about whether automated actions are still running.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

This manifest-like YAML file enables multiple trading strategies and provides parameters, but it does not document when or how these strategies should be invoked or constrained. Without explicit trigger conditions, exclusions, or narrow scope, downstream systems may interpret the configuration too broadly and activate strategies in unintended contexts.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.