Back to skill

Security audit

Vantage — HL Autonomous Trading Agent

Security checks for vulnerabilities and agentic risk

Overview

This is a real autonomous crypto trading tool, but it needs review because live risk checks can use a wallet address that is not proven to match the private key signing real orders.

Install only after reviewing the live-trading risks. Use paper mode first, keep only limited funds under the signing key, protect the .env private key, disable OpenAI fallback if trading context should stay local, update flagged dependencies, and do not run live mode until the software enforces that the wallet address used for balance/position checks matches the private key that signs orders.

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

T09 · Insecure Skill Coding Practices

Error
Location
src/index.js:170
Finding
Live Trading Risk Controls Are Not Bound to the Signing Account## Vulnerability Details **File Location**: `src/index.js:170, 219-234`; related code in `src/sizing.js:27-37` and `src/trader.js:228-286` **Vulnerability Type**: Account identity mismatch in financial risk controls **Risk Level**: High ### Vulnerable Code The autonomous loop obtains the account used for position checks and position sizing from a configurable address: ```js const walletAddress = process.env.HYPERLIQUID_WALLET_ADDRESS || ''; ``` ```js // Enforce max open positions (live only) if (!isPaper && walletAddress) { const openPos = await getPositions(walletAddress); if (openPos.length >= maxOpenPos) { console.log(` Skip ${signal.coin}: ${maxOpenPos} positions open`); continue; } } // Position sizing let sizeUsd; if (isPaper) { sizeUsd = Math.min(signal.confidence * kellyFraction * 10_000, maxPosUsd); } else { try { const { calculatePositionSize } = require('./sizing'); const sizing = await calculatePositionSize(signal.confidence, walletAddress); sizeUsd = sizing.sizeUsd; console.log(` Sizing: $${sizeUsd} (${sizing.kellySizePct}% Kelly of $${sizing.balance})`); } catch (err) { console.warn(` Sizing failed: ${err.message} -- aborting trade`); continue; } } ``` The sizing module queries the balance of that supplied address: ```js async function calculatePositionSize(confidence, walletAddress) { if (confidence <= 0 || confidence > 1) { throw new Error(`Invalid confidence value: ${confidence} (must be 0–1)`); } const maxPositionUsd = parseFloat(process.env.MAX_POSITION_SIZE_USD) || 500; const maxRiskPct = parseFloat(process.env.MAX_ACCOUNT_RISK_PCT) || 2; const kellyFraction = parseFloat(process.env.KELLY_FRACTION) || 0.25; // Fetch live balance — hard abort if this fails const balance = await getAccountBalance(walletAddress); ``` However, the resulting order is authorized using an independently configured private key: ```js async function placeOrder({ coin, isBu ...[truncated 4321 chars]
Remediation
## Remediation Suggestions 1. At live startup, derive the signer address from `HYPERLIQUID_PRIVATE_KEY` using `ethers.Wallet` and reject startup unless it exactly matches `HYPERLIQUID_WALLET_ADDRESS`. 2. Use the derived signer address—not a separately trusted environment value—for every balance, position, and exposure query. 3. Construct a single immutable signer context containing the private key and derived address, then pass that context through sizing and execution functions. 4. Add a defense-in-depth identity check inside `placeOrder()` so direct callers cannot bypass the startup validation. 5. Before signing each order, query the signer account's current positions and balance and enforce `MAX_OPEN_POSITIONS`, `MAX_ACCOUNT_RISK_PCT`, and the absolute position cap against that same identity. 6. Treat failure to derive the signer address, query its account state, or verify identity equality as fail-closed conditions. 7. Add automated tests covering mismatched addresses, missing addresses, stale configuration, direct invocation of `placeOrder()`, and signer-account risk-limit enforcement. A suitable startup pattern is: ```js const { Wallet } = require('ethers'); const privateKey = process.env.HYPERLIQUID_PRIVATE_KEY; const configuredAddress = process.env.HYPERLIQUID_WALLET_ADDRESS; const signerAddress = new Wallet(privateKey).address; if ( !configuredAddress || signerAddress.toLowerCase() !== configuredAddress.toLowerCase() ) { throw new Error( 'HYPERLIQUID_WALLET_ADDRESS does not match HYPERLIQUID_PRIVATE_KEY' ); } // Use signerAddress for all subsequent account-state queries. ```
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (59)

Credential Access

High
Category
Privilege Escalation
Content
**Step 2 — Configure your environment**
```bash
cp .env.example .env
```
Open `.env` and fill in at minimum:
- `HYPERLIQUID_PRIVATE_KEY` — your Hyperliquid account private key
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The Hyperliquid-focused description does not disclose THORNode/NineRealms network use, swap memo construction, or inbound vault metadata retrieval. Concealing cross-chain functionality is particularly dangerous in a wallet-integrated skill because it changes the transaction surface, counterparties, and irreversible fund movement risks users are consenting to.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The Hyperliquid-focused description does not disclose THORNode/NineRealms network use, swap memo construction, or inbound vault metadata retrieval. Concealing cross-chain functionality is particularly dangerous in a wallet-integrated skill because it changes the transaction surface, counterparties, and irreversible fund movement risks users are consenting to.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The Hyperliquid-focused description does not disclose THORNode/NineRealms network use, swap memo construction, or inbound vault metadata retrieval. Concealing cross-chain functionality is particularly dangerous in a wallet-integrated skill because it changes the transaction surface, counterparties, and irreversible fund movement risks users are consenting to.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The Hyperliquid-focused description does not disclose THORNode/NineRealms network use, swap memo construction, or inbound vault metadata retrieval. Concealing cross-chain functionality is particularly dangerous in a wallet-integrated skill because it changes the transaction surface, counterparties, and irreversible fund movement risks users are consenting to.

Credential Access

High
Category
Privilege Escalation
Content
```bash
npm install
cp .env.example .env
# Fill in your Hyperliquid private key + wallet address + trading limits
node src/setup-check.js   # validate before going live
```
Confidence
90% confidence
Finding
Requesting a private key in a .env file is a real credential-access pattern, and in this context it is highly sensitive because the key can authorize financial actions. Even if intended for legitimate trading, collecting raw private keys substantially raises the blast radius of any code defect, malicious dependency, or user workstation compromise.

Ae1

High
Category
analysis-evasion
Content
node src/setup-check.js # validate before going live
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/setup-check.js # validate before going live
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node src/index.js start --paper
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Known Vulnerable Dependency: axios==1.13.6 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
92% confidence
Finding
The lockfile pins axios 1.13.6, and the supplied advisories include high-risk issues such as SSRF/proxy bypass and prototype-pollution-related request manipulation. In an autonomous trading agent that makes outbound network calls and may handle API credentials, a vulnerable HTTP client materially increases risk of request redirection, credential leakage, or attacker-influenced communications.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
80% confidence
Finding
form-data 4.0.5 is reported as vulnerable to CRLF injection via unescaped multipart field names/filenames. This is only exploitable if the application builds multipart requests from attacker-controlled values, but if present it can corrupt HTTP message structure and enable request smuggling-style effects against downstream services.

Known Vulnerable Dependency: ws==8.17.1 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
87% confidence
Finding
ws 8.17.1 is flagged for memory disclosure and memory exhaustion denial-of-service issues. Since a trading agent may rely on real-time websocket market feeds, a vulnerable websocket client increases exposure to malicious or compromised upstream servers causing crashes, degraded execution, or possible unintended data exposure.

Known Vulnerable Dependency: axios==1.13.6 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
98% confidence
Finding
The manifest permits installation of axios 1.13.6, which the finding identifies as carrying multiple advisories including SSRF and man-in-the-middle/prototype-pollution-related issues. In an autonomous trading agent that consumes external market data and may interact with authenticated endpoints, a vulnerable HTTP client can enable request manipulation, credential theft, response hijacking, or malicious data injection that influences trading decisions.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The file implements THORChain quote, scan, and inbound-address utilities, which materially diverge from the advertised Hyperliquid perpetual-futures trading functionality. In an agent ecosystem, this kind of capability mismatch is dangerous because users or orchestrators may grant permissions, trust, or operational context based on the manifest, while the skill actually performs unrelated cross-chain routing and external network access.

Credential Access

High
Category
Privilege Escalation
Content
```bash
npm install
cp .env.example .env
# Fill in your Hyperliquid private key + wallet address + trading limits
node src/setup-check.js   # validate before going live
```
Confidence
88% confidence
Finding
The documentation instructs users to place a Hyperliquid private key into a local .env file to enable signed order execution. While common in developer tooling, this is still credential exposure risk because .env files are easily leaked through shell history, backups, screenshots, misconfigured repos, or downstream tooling, and here the secret directly controls trading funds.

Credential Access

High
Category
Privilege Escalation
Content
async function getPositions(walletAddress) {
  if (!walletAddress) {
    return [
      { coin: 'DEMO', side: 'long', size: 0, entryPrice: 0, unrealisedPnl: 0, note: 'Set HYPERLIQUID_WALLET_ADDRESS in .env for live positions' },
    ];
  }
  const data = await post({ type: 'clearinghouseState', user: walletAddress });
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
async function getPositions(walletAddress) {
  if (!walletAddress) {
    return [
      { coin: 'DEMO', side: 'long', size: 0, entryPrice: 0, unrealisedPnl: 0, note: 'Set HYPERLIQUID_WALLET_ADDRESS in .env for live positions' },
    ];
  }
  const data = await post({ type: 'clearinghouseState', user: walletAddress });
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
* @returns {{ valid: boolean, address?: string, error?: string }}
 */
function validatePrivateKey(key) {
  if (!key) return { valid: false, error: 'HYPERLIQUID_PRIVATE_KEY is not set in .env' };

  if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
    return {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README states that OpenAI may be used as a fallback despite marketing the agent as running locally, but it does not clearly warn users that trading signals, positions, or other decision-context data could be transmitted to a third-party cloud service. In a financial trading agent that handles private-key-backed execution, this omission can mislead users about data exposure and privacy boundaries, increasing the risk of unintended off-machine disclosure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises behavior that clearly requires environment-variable access and outbound networking, but it does not declare any explicit tool scope or permissions. That weakens sandboxing and user review because operators cannot easily see or constrain what resources the skill expects to access before installation or execution.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/hyperliquid.js:14

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/thorchain.js:11