security: add safe.ReadAllLimited — bound all HTTP response body reads to 10MB

- Created safe/io.go with ReadAllLimited helper (default 10MB limit)
- Replaced 62 unbounded io.ReadAll(resp.Body) calls across 32 files
- Covers all exchange traders (Hyperliquid, Bybit, Binance, OKX, Aster,
  KuCoin, Gate, Bitget, Lighter, Indodax), providers (CoinAnk, Alpaca,
  TwelveData), MCP client/x402, market data, wallet, telegram, kernel
- Prevents OOM from malicious/buggy exchange API responses
- Previously fixed: brain.go, sentinel.go already had manual LimitReader
This commit is contained in:
shinchan-zhai
2026-03-23 10:55:03 +08:00
parent 1d0d6f7afd
commit 982ee668c9
33 changed files with 120 additions and 89 deletions

View File

@@ -1,10 +1,10 @@
package hyperliquid
import (
"nofx/safe"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"nofx/logger"
"nofx/trader/types"
@@ -224,7 +224,7 @@ func (t *HyperliquidTrader) getXYZDexBalance() (accountValue float64, unrealized
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return 0, 0, nil, fmt.Errorf("failed to read response: %w", err)
}
@@ -315,7 +315,7 @@ func (t *HyperliquidTrader) getXyzMarketPrice(coin string) (float64, error) {
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return 0, fmt.Errorf("failed to read response: %w", err)
}

View File

@@ -1,10 +1,10 @@
package hyperliquid
import (
"nofx/safe"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"nofx/logger"
"nofx/trader/types"
@@ -452,7 +452,7 @@ func (t *HyperliquidTrader) cancelXyzOrders(coin string) error {
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %w", err)
}
@@ -545,7 +545,7 @@ func (t *HyperliquidTrader) cancelXyzOrder(oid int64) error {
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %w", err)
}
@@ -686,7 +686,7 @@ func (t *HyperliquidTrader) placeXyzOrder(coin string, isBuy bool, size float64,
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
@@ -850,7 +850,7 @@ func (t *HyperliquidTrader) placeXyzTriggerOrder(coin string, isBuy bool, size f
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}

View File

@@ -1,10 +1,10 @@
package hyperliquid
import (
"nofx/safe"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"nofx/logger"
"strings"
@@ -74,7 +74,7 @@ func (t *HyperliquidTrader) fetchXyzMeta() error {
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
body, err := safe.ReadAllLimited(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response: %w", err)
}