Back to skill

Security audit

Quant Trading System

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a simulated trading skill, but it includes under-disclosed unauthenticated dashboard servers exposed beyond localhost.

Review before installing or running. Treat it as a paper-trading/demo tool, not a safe live trading system. Do not expose the dashboard on an untrusted network; bind it to 127.0.0.1, add authentication, and avoid importing dashboard.py unless you intend to start a server. Confirm the Hyperliquid API dependency is acceptable in your environment and do not rely on the mock/simplified indicators for financial decisions.

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

T09 · Insecure Skill Coding Practices

Note
Location
dashboard.py:43
Finding
Unauthenticated dashboard server binds to all network interfaces<![CDATA[ ## Vulnerability Details **File Location**: `dashboard.py:43-45` **Vulnerability Type**: Unauthenticated network service exposure **Risk Level**: Low ### Vulnerable Code ```python print(f"Starting dashboard on http://localhost:{PORT}") with socketserver.TCPServer(("", PORT), Handler) as httpd: httpd.serve_forever() ``` The exposed handler provides dashboard information without authentication: ```python def do_GET(self): if self.path == "/status": self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() data = {"capital": 10000, "return": 0, "positions": 0, "strategies": 10} self.wfile.write(json.dumps(data).encode()) elif self.path == "/strategies": self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() data = ["momentum", "mean_reversion", "breakout", "macd_cross", "supertrend", "rsi_extreme", "bollinger_bounce", "trend_following", "volatility_breakout", "ai_hybrid"] self.wfile.write(json.dumps(data).encode()) ``` ### Technical Analysis Passing an empty host string to `socketserver.TCPServer` binds the server to all available network interfaces, rather than only the loopback interface. This conflicts with the displayed `localhost` URL and may cause users to believe the dashboard is locally accessible only. The `/status` and `/strategies` endpoints have no authentication or authorization controls. The module also starts the server at import time because server initialization is not protected by an `if __name__ == "__main__":` guard. The currently returned information is static and not highly sensitive, which limits the immediate impact. However, the binding behavior creates an unsafe default and would expose any real account, position, or operational data subsequently added to these endpoints. ### Attack Path 1. A user starts `dashboard.py`, or another program imports it ...[truncated 820 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind to the loopback interface by default: ```python HOST = "127.0.0.1" with socketserver.TCPServer((HOST, PORT), Handler) as httpd: httpd.serve_forever() ``` 2. Protect startup with a main guard to prevent side effects during import: ```python def main(): print(f"Starting dashboard on http://127.0.0.1:{PORT}") with socketserver.TCPServer(("127.0.0.1", PORT), Handler) as httpd: httpd.serve_forever() if __name__ == "__main__": main() ``` 3. If remote dashboard access is required, require authentication and authorization, terminate TLS through a trusted reverse proxy, and restrict access with host firewall rules. 4. Avoid returning account identifiers, balances, positions, trade history, or other operational information to unauthenticated clients. 5. Clearly document the listening address and security implications of enabling remote access. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
trading_system_v3.py:89
Finding
V3 dashboard exposes unauthenticated HTTP endpoints on all interfaces<![CDATA[ ## Vulnerability Details **File Location**: `trading_system_v3.py:89-111` **Vulnerability Type**: Unauthenticated network service exposure **Risk Level**: Low ### Vulnerable Code ```python def start(self): class Handler(BaseHTTPRequestHandler): def do_GET(self): if self.path == "/status": self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(json.dumps(self.server.portfolio.get_status()).encode()) elif self.path == "/strategies": self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(json.dumps(StrategyLibrary.list_strategies()).encode()) else: self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(b"<h1>Quant Trading System V3</h1><p><a href='/status'>Status</a> | <a href='/strategies'>Strategies</a></p>") server = HTTPServer(("0.0.0.0", self.port), Handler) thread = threading.Thread(target=server.serve_forever) thread.daemon = True thread.start() return f"Dashboard: http://localhost:{self.port}" ``` ### Technical Analysis The V3 dashboard explicitly binds to `0.0.0.0`, making the HTTP server reachable through every configured network interface. Nevertheless, the returned message advertises a `localhost` URL, which can obscure the actual exposure. No authentication or authorization checks are performed before serving the root page and strategy list. The `/status` route is intended to expose portfolio status, although the shown implementation does not assign `portfolio` to the `HTTPServer` object and may therefore raise an `AttributeError` when that route is requested. That defect does not remove the network exposure of the ...[truncated 1308 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind locally unless remote exposure is explicitly requested: ```python server = HTTPServer(("127.0.0.1", self.port), Handler) ``` 2. Require explicit configuration to listen on external interfaces and warn the operator when doing so. 3. Add authentication and route-level authorization before exposing portfolio or trading information. 4. Use HTTPS through a properly configured reverse proxy for any non-loopback deployment. 5. Restrict the listening port through host and network firewall rules. 6. Correctly attach required application state without making it public by default: ```python server = HTTPServer(("127.0.0.1", self.port), Handler) server.portfolio = self.portfolio ``` 7. Return controlled error responses rather than allowing handler exceptions to terminate individual request processing. 8. Retain a reference to the server and provide an explicit shutdown method for safe lifecycle management. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trading_system_v2.py:26
Finding
Unvalidated zero market price causes division-by-zero denial of service<![CDATA[ ## Vulnerability Details **File Location**: `trading_system_v2.py:26-33`, `trading_system_v2.py:246-248`, and `trading_system_v2.py:376-380` **Vulnerability Type**: Improper input validation and exception handling **Risk Level**: Medium ### Vulnerable Code Market-data failures are converted into a numeric zero: ```python def get_realtime_price(self, symbol: str) -> float: try: r = requests.post("https://api.hyperliquid.xyz/info", json={"type": "allMids"}, timeout=10) data = r.json() coin = symbol.replace("USDT", "").replace("USDC", "") return float(data.get(coin, 0)) except: return 0 ``` The value is then used as a divisor without validation: ```python def calculate_position_size(self, balance: float, price: float, risk_pct: float = 0.1) -> float: size = balance * risk_pct / price return size ``` The main workflow passes the potentially zero price directly into the risk manager: ```python risk_result = self.risk_manager.run( strategy_result, self.execution_agent.balance, data_result.get("price", 0) ) ``` ### Technical Analysis `get_realtime_price()` returns `0` whenever: - The external API request times out or fails. - The response is not valid JSON. - The requested asset is missing from the response. - The returned value cannot be converted to a floating-point number. - Any other exception occurs inside the broad `except` block. The workflow does not distinguish a valid market price from an error sentinel. `RiskManager.calculate_position_size()` subsequently divides the balance allocation by that value, causing a deterministic `ZeroDivisionError`. The broad exception handler suppresses the original error and removes diagnostic information. The code also does not call `raise_for_status()`, validate the response schema, or reject non-finite and non-positive market prices. ### Attack Path 1. The trading workflow is run in its default `trade` mode. ...[truncated 1172 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate market prices before using them: ```python import math def calculate_position_size(self, balance: float, price: float, risk_pct: float = 0.1) -> float: if not math.isfinite(price) or price <= 0: raise ValueError("Market price must be a finite positive number") if not 0 < risk_pct <= self.max_position_pct: raise ValueError("Risk percentage is outside the permitted range") return balance * risk_pct / price ``` 2. Do not use `0` as an error sentinel. Return `None`, use a structured result, or raise a specific exception. 3. Catch only expected request and parsing exceptions: ```python from requests import RequestException def get_realtime_price(self, symbol: str) -> float: try: response = requests.post( "https://api.hyperliquid.xyz/info", json={"type": "allMids"}, timeout=10, ) response.raise_for_status() data = response.json() coin = symbol.replace("USDT", "").replace("USDC", "") price = float(data[coin]) if not math.isfinite(price) or price <= 0: raise ValueError("Invalid market price") return price except (RequestException, KeyError, TypeError, ValueError) as exc: raise RuntimeError(f"Unable to obtain a valid price for {symbol}") from exc ``` 4. Abort the workflow cleanly when market data is unavailable and avoid strategy or execution processing with invalid values. 5. Add retry logic with bounded exponential backoff for transient failures. 6. Log sanitized diagnostic information so operators can distinguish timeouts, HTTP errors, schema changes, and unsupported symbols. 7. Add tests for zero, negative, missing, infinite, `NaN`, malformed, and timeout market-price cases. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • 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 (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Exposing an undeclared HTTP server on 0.0.0.0 while presenting the skill as a trading system materially changes its security profile. In context, this is especially risky because a finance-themed skill may be trusted more readily, and an unexpected network service can leak state, invite probing, or serve as a foothold on the host.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Exposing an undeclared HTTP server on 0.0.0.0 while presenting the skill as a trading system materially changes its security profile. In context, this is especially risky because a finance-themed skill may be trusted more readily, and an unexpected network service can leak state, invite probing, or serve as a foothold on the host.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Exposing an undeclared HTTP server on 0.0.0.0 while presenting the skill as a trading system materially changes its security profile. In context, this is especially risky because a finance-themed skill may be trusted more readily, and an unexpected network service can leak state, invite probing, or serve as a foothold on the host.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Exposing an undeclared HTTP server on 0.0.0.0 while presenting the skill as a trading system materially changes its security profile. In context, this is especially risky because a finance-themed skill may be trusted more readily, and an unexpected network service can leak state, invite probing, or serve as a foothold on the host.

Missing User Warnings

High
Confidence
95% confidence
Finding
The script performs automated trade execution based solely on internally generated signals and immediately opens positions without any explicit user confirmation, dry-run mode, or safety interlock. In a trading skill context, these are potentially irreversible financial operations that can cause direct monetary loss if the tool is invoked unintentionally, with stale/manipulated data, or under incorrect assumptions about whether it is in simulation versus live mode.

Missing User Warnings

High
Confidence
93% confidence
Finding
The skill automatically opens positions based on generated signals without any explicit user confirmation, safety interlock, or clear warning that trading actions will occur. In the context of an automated trading system, this materially increases the risk of unintended financial actions and makes the misleading mock-indicator logic more dangerous.

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill advertises network-relevant behavior and the broader analysis indicates external connectivity or server functionality, but the manifest declares no explicit tool scope or permissions. This is dangerous because it prevents users and hosting platforms from understanding or constraining what the skill may access over the network.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill presents automated order placement and risk controls without any prominent warning that it may influence financial decisions or simulate/execute trades. In a trading context, this is dangerous because users may enable automation without understanding loss risk, execution semantics, or whether safeguards are real versus marketing text.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The code makes an outbound request to a third-party trading data API without prominent disclosure to the user, which can surprise users in restricted or privacy-sensitive environments. In an automated trading skill, undisclosed network access is more dangerous because it directly influences trading decisions and can expose usage metadata or fail in ways that silently alter behavior.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            coin = symbol.replace("USDT", "")
            return float(r.json().get(coin, 0))
Confidence
72% confidence
Finding
This finding highlights the hardcoded external domain used for market-data retrieval. Hardcoded third-party endpoints are not inherently malicious, but in a trading automation tool they increase operational and security risk because users may be unaware of outbound connectivity and the tool has no clear mechanism to verify or substitute the data source if it becomes untrustworthy.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            coin = symbol.replace("USDT", "")
            return float(r.json().get(coin, 0))
Confidence
80% confidence
Finding
This finding highlights the hardcoded external domain used for market-data retrieval. Hardcoded third-party endpoints are not inherently malicious, but in a trading automation tool they increase operational and security risk because users may be unaware of outbound connectivity and the tool has no clear mechanism to verify or substitute the data source if it becomes untrustworthy.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            coin = symbol.replace("USDT", "")
            return float(r.json().get(coin, 0))
Confidence
72% confidence
Finding
This finding highlights the hardcoded external domain used for market-data retrieval. Hardcoded third-party endpoints are not inherently malicious, but in a trading automation tool they increase operational and security risk because users may be unaware of outbound connectivity and the tool has no clear mechanism to verify or substitute the data source if it becomes untrustworthy.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest says the skill is an 'Automated Trading System with Multi-Strategy Voting', which implies executing or coordinating trading logic. In this file, the code only starts an HTTP server and returns fixed dashboard/status content, with no trading, voting, market interaction, or live system state retrieval.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The code sends network requests to an external trading API without any user-facing disclosure. While the transmitted data here is minimal, undisclosed outbound connections in an agent skill reduce transparency and can surprise users or violate environment/network expectations.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The docstring claims indicator calculation, but the implementation uses deterministic pseudo-random RSI and MACD values instead of real market-derived indicators. In a trading skill, this is dangerous because it can mislead users into believing decisions are based on legitimate analysis, causing unsafe automated trades and financial loss.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
70% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
70% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
70% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
70% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
80% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
80% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
80% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
Confidence
80% 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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
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
def get_realtime_price(self, symbol: str) -> float:
        try:
            r = requests.post("https://api.hyperliquid.xyz/info", 
                           json={"type": "allMids"}, timeout=10)
            data = r.json()
            coin = symbol.replace("USDT", "").replace("USDC", "")
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.