Audits › Controls › API key permissions
Security · control 14 of 21
API key permissions: does your trading bot have it?
Do the docs ask for an API key without withdrawal rights and with IP restriction, does the code work with such a key, and does the code ever call withdrawal or transfer endpoints?
Why it matters
A key with withdrawal rights turns a bug or a leak into a theft.
How to check it in the code
- Read the setup docs: do they say which permissions to enable?
- Search the code for withdraw, transfer, sapi/v1/capital: it should never call them.
- Check whether an IP-restricted key is mentioned or assumed.
This is what the audit does for every bot in the list, on public code, without installing or running anything. Verdict values: present, partial, absent, not applicable, not verified. See the method.
Results across audited bots
Across 10 audited bots: 1 present, 4 partial, 1 absent, 0 not applicable, 4 not verified.
| Bot | Verdict | Evidence | Note |
|---|---|---|---|
| HKUDS/Vibe-Trading | Partial | agent/src/trading/onboarding.py: explicit setup_hint text for several connectors, e.g. Binance 'Create a read-only Spot API key; do not enable withdrawals', OKX 'do not grant Trade or Withdraw permissions', Upbit 'do not grant withdrawal permission'. GET /search/code?q=withdraw+repo:HKUDS/Vibe-Trading+language:Python returned 10 hits, none inspected as an actual withdrawal API call | Least-privilege credentials are documented policy for the connectors checked, but not exhaustively verified across all 18 connectors that the code itself never calls a withdraw/transfer endpoint. |
| hummingbot/hummingbot | Partial | GET /search/code?q="/withdraw" repo:hummingbot/hummingbot path:connector -> total_count 0 (2026-09-17) | The connector code never calls withdrawal/transfer endpoints. Whether the official docs (hummingbot.org, outside this repo) explicitly instruct users to create a no-withdrawal, IP-restricted API key was not checked in this session (budget). |
| Drakkar-Software/OctoBot | Partial | exchange_credentials_data.py only models api_key/secret/password/uid (CEX) or wallet_address/private_key (DEX) fields; GitHub code search for '.withdraw(' found a match only in a DEX blockchain_wallet_operators tentacle (on-chain, user-initiated), not in any CEX/CCXT order-execution path. | No code path was found that calls a CEX withdrawal/transfer endpoint, which reduces (but does not eliminate) the blast radius of a leaked key. Could not verify whether official setup docs instruct users to create a trade-only, IP-restricted key. |
| freqtrade/freqtrade | Partial | docs/exchanges.md, Gate.io section ('Spot Trade'/'Perpetual Futures' RW + 'Wallet' read-only + 'Account' read-only) and Bybit section ('Read-write, Contract-Orders, Contract-Positions... We do strongly recommend to limit all API keys to the IP you're going to use it from.') -- same URL as above | Per-exchange docs list minimal required scopes and none ask for withdrawal permission, but an explicit IP-restriction recommendation is only documented for Bybit, not as a universal rule for every supported exchange. |
| jesse-ai/jesse | Not verified | No withdrawal/transfer API calls exist anywhere in this repository (the only exchange driver present, Sandbox, never calls a real exchange). The real exchange integrations and their required API-key scopes are defined inside the closed-source 'jesse_live' plugin (docs.jesse.trade/docs/livetrade confirms live/paper trading 'is supported by Jesse via an official plugin' requiring a separate license). | Cannot confirm what permissions jesse_live's documentation requests or whether its code ever calls a withdrawal endpoint. |
| chrisleekr/binance-trading-bot | Present | SECURITY.md ("Compensating control" section); deploy/README.md step 8 ("IP-allowlist your Binance API key") | Documentation explicitly instructs: restrict the key to the server's IP and "do not enable withdrawal permission"; only "Spot & Margin Trading" is asked to be checked. Whether any code path ever calls a withdraw/transfer endpoint was not individually verified within budget (a repo-wide search for "withdraw" returned 16 hits, mostly documentation, not opened one by one). |
| alsk1992/CloddsBot | Absent | .env.example documents trading credentials for Polymarket/Kalshi/Manifold/Metaculus (POLY_API_KEY, POLY_PRIVATE_KEY, KALSHI_API_KEY, etc.) with no instruction to disable withdrawals or restrict the key by IP. Futures-exchange keys (Binance/Bybit/MEXC/Hyperliquid) referenced in src/execution/futures.ts are not documented in .env.example at all. | No documentation found instructing users to mint a withdrawal-disabled, IP-restricted key for any supported exchange. |
| Lumiwealth/lumibot | Not verified | GET /search/code?q=withdraw+repo:Lumiwealth/lumibot+path:lumibot/brokers -> 3 hits (alpaca.py, broker.py, and one more), not individually inspected line-by-line within the session budget. | |
| YizhiSong/FriesTrader | Not verified | README First-time setup #1: Agentic Trading 'requires a separate, dedicated account -- distinct from your regular investing account, and restricted to only the funds you put in it' (a segregation control). No API key, OAuth scope, or credential file exists anywhere in this repo to inspect. | The actual credential/scope granted to Robinhood's MCP server is configured entirely outside this repository (Robinhood's own account settings + the user's Claude Code MCP connector config) -- cannot be verified or refuted from code alone. |
| c9s/bbgo | Not verified | doc/README.md index has no dedicated API-key-permissions/security guide; pkg/cmd/withdraw.go does not exist (HTTP 404) | No documentation recommending a non-withdrawal, IP-restricted key was found, and there is no funds-withdrawal command in pkg/cmd, but a full check of every one of the 9 exchange clients for calls to withdrawal endpoints was not completed within the time/budget available. |
If your bot does not have it
The watchdog enforces daily loss, drawdown, position size and heartbeat limits from outside the bot, with a read-only key, whatever the bot's own code does.