#8084·hummingbot

Security: eval() on WebSocket message data in foxbit order book handlers

Author: theeggorchickenCreated Feb 26, 2026Updated Aug 31, 2026

Summary

Two methods in foxbit_api_order_book_data_source.py pass live WebSocket message data directly to eval(). The 'o' field of every incoming message is deserialized this way, which makes the handlers reachable code execution sinks for anyone who can influence what the exchange sends.

I sent a detailed report with reproduction steps and test artifacts to [email protected]. Happy to share more here or through a private channel.

Affected Code

File: hummingbot/connector/exchange/foxbit/foxbit_api_order_book_data_source.py

python
# Line 147 — _parse_trade_message
full_msg = eval(raw_message['o'].replace(",false,", ",False,"))

# Line 165 — _parse_order_book_diff_message
full_msg = eval(raw_message['o'])

Worth noting: the guard condition on line 146 has a logic bug.

python
if CONSTANTS.WS_SUBSCRIBE_TRADES or CONSTANTS.WS_TRADE_RESPONSE in raw_message['n']:

Since WS_SUBSCRIBE_TRADES is a non-empty string, this condition is always truthy, so eval() runs unconditionally for every incoming message regardless of event type. The fix for the logic bug is the same or operator precedence correction needed anyway: if CONSTANTS.WS_SUBSCRIBE_TRADES in raw_message['n'] or CONSTANTS.WS_TRADE_RESPONSE in raw_message['n']:.

Impact

An attacker with a MITM position on the Foxbit WebSocket connection can inject a crafted 'o' field value into any trade or order book message. eval() executes it as Python code. The official Docker image runs as root, so this is full host compromise.

Suggested Fix

python
import json

# _parse_trade_message (line 147)
full_msg = json.loads(raw_message['o'])

# _parse_order_book_diff_message (line 165)
full_msg = json.loads(raw_message['o'])

json.loads() handles all JSON value types natively. The .replace(",false,", ",False,") workaround can be dropped entirely.

I've submitted a pull request with this fix and tests.