llm-trading-agent-security

llm-trading-agent-security

熱門

自主交易代理的安全模式,適用於具備錢包或交易授權的情境。涵蓋提示注入、支出限制、發送前模擬、斷路器、MEV 保護與金鑰處理。

23萬星標
3.5萬分支
更新於 2026/7/21
SKILL.md
readonlyread-only
name
llm-trading-agent-security
description

Security patterns for autonomous trading agents with wallet or transaction authority. Covers prompt injection, spend limits, pre-send simulation, circuit breakers, MEV protection, and key handling.

version
1.0.0

LLM 交易代理安全

自主交易代理的威脅模型比一般 LLM 應用更嚴峻:一次注入或錯誤的工具路徑可能直接導致資產損失。

使用時機

  • 建構會簽署並發送交易的 AI 代理
  • 審計交易機器人或鏈上執行助手
  • 為代理設計錢包金鑰管理
  • 讓 LLM 能夠進行委託下單、兌換或金庫操作

運作方式

層層防禦。沒有任何單一檢查就足夠。將提示衛生、支出政策、模擬、執行限制與錢包隔離視為獨立控制項。

範例

將提示注入視為金融攻擊

import re

INJECTION_PATTERNS = [
    r'ignore (previous|all) instructions',
    r'new (task|directive|instruction)',
    r'system prompt',
    r'send .{0,50} to 0x[0-9a-fA-F]{40}',
    r'transfer .{0,50} to',
    r'approve .{0,50} for',
]

def sanitize_onchain_data(text: str) -> str:
    for pattern in INJECTION_PATTERNS:
        if re.search(pattern, text, re.IGNORECASE):
            raise ValueError(f"潛在提示注入:{text[:100]}")
    return text

不要盲目地將代幣名稱、交易對標籤、Webhook 或社群動態注入到可執行的提示中。

嚴格支出限制

from decimal import Decimal

MAX_SINGLE_TX_USD = Decimal("500")
MAX_DAILY_SPEND_USD = Decimal("2000")

class SpendLimitError(Exception):
    pass

class SpendLimitGuard:
    def check_and_record(self, usd_amount: Decimal) -> None:
        if usd_amount > MAX_SINGLE_TX_USD:
            raise SpendLimitError(f"單筆交易 ${usd_amount} 超過上限 ${MAX_SINGLE_TX_USD}")

        daily = self._get_24h_spend()
        if daily + usd_amount > MAX_DAILY_SPEND_USD:
            raise SpendLimitError(f"每日上限:${daily} + ${usd_amount} > ${MAX_DAILY_SPEND_USD}")

        self._record_spend(usd_amount)

發送前模擬

class SlippageError(Exception):
    pass

async def safe_execute(self, tx: dict, expected_min_out: int | None = None) -> str:
    sim_result = await self.w3.eth.call(tx)

    if expected_min_out is None:
        raise ValueError("發送前必須設定 min_amount_out")

    actual_out = decode_uint256(sim_result)
    if actual_out < expected_min_out:
        raise SlippageError(f"模擬結果:{actual_out} < {expected_min_out}")

    signed = self.account.sign_transaction(tx)
    return await self.w3.eth.send_raw_transaction(signed.raw_transaction)

斷路器

class TradingCircuitBreaker:
    MAX_CONSECUTIVE_LOSSES = 3
    MAX_HOURLY_LOSS_PCT = 0.05

    def check(self, portfolio_value: float) -> None:
        if self.consecutive_losses >= self.MAX_CONSECUTIVE_LOSSES:
            self.halt("連續虧損次數過多")

        if self.hour_start_value <= 0:
            self.halt("hour_start_value 無效")
            return

        hourly_pnl = (portfolio_value - self.hour_start_value) / self.hour_start_value
        if hourly_pnl < -self.MAX_HOURLY_LOSS_PCT:
            self.halt(f"每小時損益 {hourly_pnl:.1%} 低於門檻")

錢包隔離

import os
from eth_account import Account

private_key = os.environ.get("TRADING_WALLET_PRIVATE_KEY")
if not private_key:
    raise EnvironmentError("未設定 TRADING_WALLET_PRIVATE_KEY")

account = Account.from_key(private_key)

使用專用的熱錢包,僅存放必要的會話資金。切勿讓代理指向主要金庫錢包。

MEV 與截止時間保護

import time

PRIVATE_RPC = "https://rpc.flashbots.net"
MAX_SLIPPAGE_BPS = {"stable": 10, "volatile": 50}
deadline = int(time.time()) + 60

部署前檢查清單

  • 外部資料在進入 LLM 上下文前已進行清理
  • 支出限制獨立於模型輸出執行
  • 交易在發送前已模擬
  • min_amount_out 為必填
  • 斷路器在回撤或無效狀態時停止
  • 金鑰來自環境變數或密碼管理器,絕不來自程式碼或日誌
  • 在適當時使用私有記憶體池或受保護路由
  • 根據策略設定滑點與截止時間
  • 所有代理決策皆記錄審計日誌,不僅是成功發送