Back to skill

Security audit

Nautilus Trader

Security checks for vulnerabilities and agentic risk

Overview

This skill is coherent with live trading, but its examples and patch can perform real Hyperliquid mainnet actions with wallet credentials and too little user confirmation.

Review this carefully before installing. Use only testnet or paper trading until you have added explicit mainnet flags, dry-run mode, wallet and vault confirmation, order-size and leverage limits, and dependency pinning. Do not run the included live_trading.py or set_leverage.py with a funded wallet unless you intend real mainnet trades and leverage changes.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/hyperliquid_patch.py:116
Finding
Incomplete exchange response handling can desynchronize local and live trading state<![CDATA[ ## Vulnerability Details **File Location**: `references/hyperliquid_patch.py`, lines 116-145 **Vulnerability Type**: Incomplete order and fill state reconciliation **Risk Level**: High ### Vulnerable Code ```python result = exchange.order( name=symbol, is_buy=is_buy, sz=size, limit_px=float(limit_price), order_type=order_type, reduce_only=order.is_reduce_only, ) if result.get("status") == "ok": statuses = result.get("response", {}).get("data", {}).get("statuses", []) if statuses: s = statuses[0] if "error" in s: raise ValueError(s["error"]) venue_id = str(s.get("resting", s.get("filled", {})).get("oid", order.client_order_id)) else: venue_id = str(order.client_order_id) self.generate_order_accepted( strategy_id=order.strategy_id, instrument_id=order.instrument_id, client_order_id=order.client_order_id, venue_order_id=VenueOrderId(venue_id), ts_event=self._clock.timestamp_ns(), ) else: raise ValueError(str(result)) ``` ### Technical Analysis The patch bypasses the normal NautilusTrader Hyperliquid order-submission implementation and directly calls the Hyperliquid SDK. However, it treats both resting and immediately filled orders as merely accepted. When the exchange returns a `filled` response, the code extracts only the order identifier and calls `generate_order_accepted`. It does not generate an order-filled event or record the executed quantity, execution price, fees, remaining quantity, or resulting position. Consequently, NautilusTrader's cache, execution engine, risk engine, and strategy can retain state that differs from the actual exchange account. The project documentation also states that the patch has no position synchronization on reconnect. This increases the likelihood that state divergence will persist after an interruption. ### Attack Path 1. A live strategy submits a market or marketable limit or ...[truncated 1321 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement complete translation of every Hyperliquid SDK response into the appropriate NautilusTrader lifecycle events: - Order accepted. - Order rejected. - Order filled or partially filled. - Order canceled or expired. 2. For fills, propagate the actual venue order ID, trade ID, executed quantity, execution price, commission, liquidity side, and event timestamp. 3. Do not treat an empty or unrecognized status list as successful acceptance. Reject the local command or mark it unresolved until reconciliation completes. 4. Query the exchange after ambiguous responses and reconcile the order using its client or venue order ID. 5. Add startup and reconnect reconciliation for open orders, fills, balances, and positions before permitting new submissions. 6. Block new orders when local and exchange state cannot be reconciled. 7. Add unit and integration tests covering resting, filled, partially filled, rejected, malformed, timed-out, and duplicate-response cases. 8. Avoid replacing a private adapter method unless the replacement preserves the adapter's complete execution-state contract. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/live_trading.py:51
Finding
Example scripts execute financially consequential mainnet actions without explicit confirmation<![CDATA[ ## Vulnerability Details **File Locations**: - `references/live_trading.py`, lines 51-64 and 88-94 - `references/set_leverage.py`, lines 14-16 and 29-32 **Vulnerability Type**: Unsafe mainnet defaults and missing execution safeguards **Risk Level**: High ### Vulnerable Code From `references/live_trading.py`: ```python def _place_test_order(self): order = self.order_factory.market( instrument_id=self.instrument_id, order_side=OrderSide.BUY, quantity=self.instrument.make_qty(self.trade_size), time_in_force=TimeInForce.IOC, ) self.submit_order(order) self.log.info(f"Submitted: {order}") ``` ```python data_config = HyperliquidDataClientConfig( wallet_address=vault, is_testnet=False, ) exec_config = HyperliquidExecClientConfig( wallet_address=vault, private_key=pk, is_testnet=False, ) ``` From `references/set_leverage.py`: ```python SYMBOL = "SOL" LEVERAGE = 10 IS_CROSS = True # True for cross margin, False for isolated ``` ```python account = Account.from_key(pk) exchange = Exchange(account, constants.MAINNET_API_URL) result = exchange.update_leverage(LEVERAGE, SYMBOL, is_cross=IS_CROSS) ``` ### Technical Analysis The live-trading example explicitly configures both clients for mainnet and submits a market buy automatically when the first bar is processed. Although the method is named `_place_test_order`, it is not a simulated or testnet order. The leverage script similarly connects directly to `MAINNET_API_URL` and changes SOL leverage to 10x cross margin as soon as the script is run. Cross margin can expose shared account collateral rather than limiting risk to an isolated position. Neither script requires: - An explicit mainnet command-line option. - Interactive confirmation. - Verification of the expected wallet or vault. - A maximum notional or account-exposure check. - A dry-run mode. - Confirmation of the symbol, side, size, leverage, or margin mode. The actions are ...[truncated 1716 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default every example to Hyperliquid testnet. 2. Require an explicit command-line flag such as `--mainnet` before selecting the mainnet endpoint. 3. Require a second explicit acknowledgment, such as `--confirm-live-trading`, or an interactive confirmation displaying: - Wallet and vault addresses. - Network. - Instrument. - Side. - Quantity and estimated notional. - Leverage and margin mode. 4. Rename `_place_test_order` if it can execute a live order; the name must clearly identify it as a real mainnet action. 5. Add a dry-run mode that logs the proposed request without signing or submitting it. 6. Apply conservative configurable limits for order quantity, notional exposure, cumulative exposure, leverage, and slippage. 7. Refuse mainnet execution when the wallet, vault, symbol, or account does not match an explicit allowlist. 8. Make isolated margin and low leverage the safer example defaults; require separate confirmation for cross margin. 9. Retrieve and display existing positions and leverage before changing account configuration. 10. Document prominently that environment credentials authorize real trades and that the examples are not simulations. ]]>

T08 · Insecure Dependencies

Warning
Location
references/requirements.txt:2
Finding
Wallet-sensitive trading dependencies are not reproducibly pinned<![CDATA[ ## Vulnerability Details **File Locations**: - `references/requirements.txt`, lines 2-9 - `SKILL.md`, lines 41-47 - `references/README.md`, line 23 **Vulnerability Type**: Unpinned security-sensitive dependencies and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code From `references/requirements.txt`: ```text # Core nautilus_trader>=1.222.0,<1.223.0 # Hyperliquid SDK hyperliquid-python-sdk>=0.10.0 eth-account>=0.11.0 # Environment python-dotenv>=1.0.0 ``` From `SKILL.md`: ```bash # NautilusTrader (backtesting + live trading framework) pip install nautilus_trader # Hyperliquid SDK (for live trading patch) pip install hyperliquid-python-sdk eth-account python-dotenv # Data handling pip install pandas numpy ``` From `references/README.md`: ```bash pip install nautilus_trader hyperliquid-python-sdk eth-account python-dotenv ``` ### Technical Analysis The Hyperliquid SDK and `eth-account` receive or process a wallet private key and participate in signing live trading actions. `python-dotenv` loads that key into the process environment, while NautilusTrader controls live order execution. Despite their security-sensitive role: - Most dependencies have no upper version bound. - None are pinned to an exact audited version. - No package hashes are provided. - No lockfile or reproducible environment is included. - The primary documentation recommends entirely unpinned installation commands. A future release can therefore be installed automatically without review. This creates both compatibility and supply-chain risk. Any dependency executes with the same operating-system privileges as the Python process and may read environment variables, files available to the user, or modify the behavior of signed order requests. No evidence was found that the currently named packages are typosquatted or malicious. The vulnerability is the inability to reproduce and constrain the reviewed dependency set. ### Attack Path 1. An attacker compromi ...[truncated 1334 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin all direct dependencies to exact, reviewed versions. 2. Generate and commit a lockfile containing the full transitive dependency graph. 3. Require cryptographic hashes during installation, for example through a hash-locked requirements file and `pip --require-hashes`. 4. Use a trusted package index explicitly and prevent unexpected fallback to additional indexes. 5. Review release provenance, signatures, maintainers, and package ownership for wallet-sensitive dependencies. 6. Run vulnerability and dependency-confusion checks in CI. 7. Test dependency upgrades in testnet and require manual security review before updating the lockfile. 8. Isolate signing from the main application where possible, using a restricted signer or wallet with narrowly limited trading authority and funds. 9. Avoid exposing unrelated secrets to the trading process; launch it with a minimal environment. 10. Update all installation examples to use the locked installation mechanism rather than unrestricted `pip install` commands. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (655)

Credential Access

High
Category
Privilege Escalation
Content
```
your_trading_project/
├── .env                        # Credentials (gitignored)
├── hyperliquid_patch.py        # SDK patch for live trading
├── heiken_ashi.py              # Heiken Ashi indicator
├── my_strategy.py              # Strategy implementation
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```
your_trading_project/
├── .env                        # Credentials (gitignored)
├── hyperliquid_patch.py        # SDK patch for live trading
├── heiken_ashi.py              # Heiken Ashi indicator
├── my_strategy.py              # Strategy implementation
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
# Nautilus_Trader - Api

**Pages:** 17

---

## Serialization

**URL:** https://nautilustrader.io/docs/latest/api_reference/serialization

**Contents:**
- Serialization
  - register_serializable_type(type cls: type, to_dict: Callable[[Any], dict[str, Any]], from_dict: Callable[[dict[str, Any]], Any]) → void​
  - class MsgSpecSerializer​
    - deserialize(self, bytes obj_bytes)​
    - serialize(self, obj) → bytes​
    - timestamps_as_iso8601​
    - timestamps_as_str​
  - class Serializer​
    - WARNING​
    - deserialize(self, bytes obj_bytes)​

The serialization subpackage groups all serialization components and serializer implementations.

Base classes are defined which can allow for other serialization implementations beside the built-in specification serializers.

Register the given type with the global serialization type maps.

The type will also be registered as an exter
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Memory Manipulation

High
Category
Memory Poisoning
Content
WebSocket clients handle real-time streaming data and require careful management of connection state, authentication, subscriptions, and reconnection logic.

WebSocket clients typically don't need the inner/outer pattern since they're not frequently cloned. Use a single struct with clear state management.

Handle authentication separately from subscriptions.
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Missing User Warnings

High
Confidence
97% confidence
Finding
The file describes deleting data within a specified time range across the catalog and for specific data classes/instruments, but it does not include any caution that this is destructive or potentially irreversible. For markdown files, omission of warnings about destructive effects on user data is a reportable missing-warning issue.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
# Nautilus_Trader - Concepts

**Pages:** 19

---

## Strategies

**URL:** https://nautilustrader.io/docs/latest/concepts/strategies

**Contents:**
- Strategies
- Strategy implementation​
  - Handlers​
    - Stateful actions​
    - Data handling​
    - Order management​
    - Position management​
    - Generic event handling​
    - Handler example​
  - Clock and timers​

The heart of the NautilusTrader user experience is in writing and working with trading strategies. Defining a strategy involves inheriting the Strategy class and implementing the methods required by the strategy's logic.

Relationship with actors: The Strategy class inherits from Actor, which means strategies have access to all actor functionality plus order management capabilities.

We reco
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Ae3

High
Category
analysis-evasion
Confidence
90% confidence
Finding
Text artifact contains embedded NUL bytes

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
# Nautilus_Trader - Data

**Pages:** 12

---

## OKX

**URL:** https://nautilustrader.io/docs/latest/integrations/okx

**Contents:**
- OKX
- Overview​
- Examples​
  - Product support​
- Symbology​
  - Symbol format by instrument type​
    - SPOT​
    - SWAP (Perpetual Futures)​
    - FUTURES (Dated Futures)​
    - OPTIONS​

Founded in 2017, OKX is a leading cryptocurrency exchange offering spot, perpetual swap, futures, and options trading. This integration supports live market data ingest and order execution on OKX.

This adapter is implemented in Rust, with optional Python bindings for ease of use in Python-based workflows. It does not require external OKX client libraries—the core components are compiled as a static
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Ae3

High
Category
analysis-evasion
Confidence
96% confidence
Finding
The file contains an embedded NUL byte in rendered documentation text ('Binary options\0'). Hidden control characters are dangerous in agent-consumed artifacts because parsers, tokenizers, scanners, or downstream tools may truncate, mis-parse, or treat surrounding content inconsistently, creating opportunities for content smuggling or analysis evasion. In a skill/reference file, that makes the artifact less trustworthy and can interfere with security tooling.

Hidden Instructions

High
Category
Prompt Injection
Content
- Polymarket
- Installation​
- Examples​
- Binary options​
- Polymarket documentation​
- Overview​
- USDC.e (PoS)​
Confidence
95% confidence
Finding
This line combines a hidden formatting character with an embedded NUL byte in the phrase 'Binary options\0', making it more than a mere typography artifact. Control characters in agent-readable docs can cause parser differentials, truncation, or scanner bypasses, which is a meaningful content-integrity risk even if likely introduced accidentally.

Missing User Warnings

High
Confidence
97% confidence
Finding
The live trading example is wired for is_testnet=False, loads a private key, builds a trading node, and calls node.run() without a conspicuous warning that this starts real mainnet trading. In this skill context, that is especially dangerous because the code is presented as a complete ready-to-run example and includes an auto-applied execution patch, making accidental deployment more likely.

Lp1

High
Category
MCP Least Privilege
Confidence
89% confidence
Finding
This file reads sensitive credentials from environment variables via `os.getenv("HYPERLIQUID_PK")` and uses them to authenticate a live trading client, but the capability is not declared. In an agent skill context, undeclared environment access is dangerous because it can silently consume secrets available to the runtime and enable real-money actions without explicit permission boundaries.

Missing User Warnings

High
Confidence
97% confidence
Finding
This example places a real IOC market buy order automatically on the first bar in a live-trading script, with no interactive confirmation, feature flag, dry-run safeguard, or prominent warning to the user. In the context of an agent skill meant to help users build and deploy trading strategies, that makes accidental real-money execution materially more likely, especially if a user copies the example verbatim.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
# Nautilus_Trader - Other

**Pages:** 15

---

## Release Notes Guide

**URL:** https://nautilustrader.io/docs/latest/developer_guide/releases

**Contents:**
- Release Notes Guide
- Sections​
  - Enhancements​
  - Breaking Changes​
  - Security​
  - Fixes​
  - Internal Improvements​
  - Documentation Updates​
  - Deprecations​
- Attribution​

This guide documents the standards for writing release notes in RELEASES.md.

Use the following sections in this order:

Omit sections that have no items for a given release.

New features and user-visible improvements.

Changes that may break existing code.

Security hardening and fixes that prevent crashes, undefined behavior, or data corruption. Includes significant hardening improvements elevated from Internal Improveme
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Credential Access

High
Category
Privilege Escalation
Content
You can run nautilus --help to view the CLI structure and available command groups:

These commands handle bootstrapping the PostgreSQL database. To use them, you need to provide the correct connection configuration, either through command-line arguments or a .env file located in the root directory or the current working directory.

List of commands are:
Confidence
72% confidence
Finding
The documentation instructs users to provide database connection configuration through command-line arguments or a .env file in the project/current directory. In agent or shared workspace contexts, encouraging local .env-based secret storage without caution can expose credentials through accidental commits, workspace leakage, or tool access to working-directory secrets.

Credential Access

High
Category
Privilege Escalation
Content
def main():
    pk = os.getenv("HYPERLIQUID_PK")
    if not pk:
        print("Set HYPERLIQUID_PK in environment or .env")
        return

    if not pk.startswith("0x"):
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
**Contents:**
- Trading
  - class Controller​
    - create_actor(actor: Actor, start: bool = True) → None​
    - create_actor_from_config(actor_config: ImportableActorConfig, start: bool = True) → None​
    - create_strategy(strategy: Strategy, start: bool = True) → None​
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Static analysis

No suspicious patterns detected.