Security: eval() on WebSocket message data in foxbit order book handlers
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
# 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.
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
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.
Source: hummingbot/hummingbot