An exchange API key is not a password. It is a scoped credential that lets software act on your account without your login. That is exactly what makes it useful to a bot and dangerous when it leaks. Most account-drain stories are not sophisticated hacks. They are keys that were pasted into a public repo, left on withdrawal permission by default, or copied to a laptop that later got infected. The fixes are boring and they work.
What can someone do with a stolen trading bot API key?
Whatever permissions you granted, and nothing more. That is the whole game. An API key carries a set of scopes, and the attacker inherits exactly those scopes. If you left withdrawal enabled, they send your balance to their own address and you are done.
The subtler attack needs only trade permission. An attacker who controls a key with order access can run a cross-trade: they buy a thin, illiquid market with your balance at an absurd price while selling the same coin from their own account. Your money walks out the door through the order book instead of the withdrawal screen. This is why "withdrawals are off, so I'm safe" is only half true. For how bots authenticate in the first place, see how bots connect to exchanges.
Disable withdrawals on every bot key
This is the single most important setting, so do it first. A trading bot places and cancels orders. It does not need to move funds off the exchange, ever. Almost no legitimate strategy requires withdrawal access from an automated key.
With withdrawal disabled, a fully compromised key still cannot send your coins anywhere. The worst an attacker can do is trade badly on your behalf, which the IP lock below largely blocks too. Many exchanges reinforce this: on Binance and others, a key with no IP restriction has withdrawal silently forced off, because an unrestricted withdrawal-enabled key is the worst possible object to hold.
If your workflow genuinely needs automated withdrawals, keep them on a separate key with an address allowlist so funds can only ever go to wallets you pre-approved.
Exchange API key permissions: the least-privilege list
Grant the minimum scope the bot actually uses. If your bot only reads prices and reports P&L, give it a read-only key and stop there. A read-only key that leaks is a non-event. Match the permission to the job:
| Permission | What it allows | Give it to a bot? |
|---|---|---|
| Read-only | Balances, positions, market data | Yes, always safe |
| Spot / margin trade | Place and cancel orders | Only if it trades spot |
| Futures / perps trade | Open and close leveraged positions | Only if it trades perps |
| Withdraw | Move funds off the exchange | No, keep it off |
Run one key per bot, not one master key shared across three strategies. Separate keys let you revoke a single compromised bot without taking your whole stack offline, and they make it obvious which bot did what in the audit log.
How do IP allowlists protect trading bot keys?
An IP allowlist tells the exchange to accept requests for a key only from specific IP addresses. Bind the key to the static IP of the machine running the bot. Now even if the key and secret leak in full, the exchange rejects every request that does not come from your server.
This is the strongest control after disabling withdrawals, because it neutralizes a leaked key rather than just limiting its damage. It is also the practical reason a server with a fixed IP beats a laptop on a home connection whose address rotates. If you are choosing where to run the bot, weigh that in VPS vs home server. One caveat: cloud IPs can change on reboot or migration, so use a reserved or elastic IP and update the allowlist if it ever moves.
Where should you store API secrets?
Not in your source code, and never in a git repository. The secret is shown once at key creation and cannot be retrieved again, which people take as a reason to paste it somewhere convenient. That somewhere is usually the problem.
- Keep the secret in an environment variable or a
.envfile, and add that file to.gitignorebefore you write a single key into it. - For anything beyond a hobby setup, use a secrets manager that encrypts at rest, so the key never sits in plaintext on disk.
- Never paste a key or secret into a chat, a screenshot, a support ticket, or a third-party "portfolio tracker" you have not vetted.
- Scan your git history, not just the current files. A secret committed months ago and later deleted is still sitting in the history for anyone with repo access.
The OWASP secrets-management guidance is the plain-English reference here, and it applies to a one-file Python bot as much as to a company. Storage discipline matters most for anything you leave running 24/7, because an always-on box is a bigger target than a script you run by hand.
On-chain bots use API wallets, not exchange keys
If your bot trades on a perp DEX instead of a centralized exchange, the security model is different and arguably better. On Hyperliquid, for example, you authorize an agent or API wallet: a separate signing key that can place trades on your account but cannot withdraw funds and holds no balance of its own. If that key leaks, an attacker can trade but cannot pull money out, and you can revoke the agent on-chain.
The trade-off is that you are now managing wallet keys and signed transactions rather than an exchange dashboard. If you are weighing the two custody models, see on-chain vs CEX bots and the specifics of the Hyperliquid tooling.
What to do if a key leaks
Move fast and in this order. Speed matters more than tidiness here.
- Delete or disable the key on the exchange immediately. Revoking it is instant and beats any cleanup.
- Check open orders and positions, and cancel anything you did not place.
- Confirm withdrawal permission was off and that no withdrawal address was added or whitelisted.
- Rotate the key, tighten the IP allowlist, and re-check that withdrawals stay disabled on the replacement.
- If the leak came from code, purge it from git history and rotate every other secret that lived in the same place.
The checklist in one place
- Withdrawal permission: off on every bot key.
- Permissions: read-only unless the bot trades, then the narrowest trade scope it needs.
- IP allowlist: on, bound to a fixed server IP.
- Secret storage: environment variable or secrets manager, never in git.
- One key per bot, so you can revoke one without killing all of them.
- Account-level 2FA on, and a plan to revoke and rotate if anything looks wrong.
None of this promises profits, and it does not fix a losing strategy. It just makes sure a bug, a bad night, or a leaked file costs you trades instead of your whole balance.
Frequently asked questions
Should a trading bot API key ever have withdrawal permission?
No, in almost every case. Bots place and cancel orders; they do not need to move funds off the exchange. Keeping withdrawal off means a fully compromised key still cannot send your coins to an attacker. If you truly need automated withdrawals, isolate them on a separate key with a pre-approved address allowlist.
What is an IP allowlist and do I need one?
An IP allowlist restricts a key so the exchange only accepts requests from specific addresses, usually your server's fixed IP. Yes, you want it. Even a fully leaked key becomes useless from any other machine. It is the strongest control after disabling withdrawals, which is why a static-IP server beats a rotating home connection.
Where is the safest place to store my API secret?
Outside your code. Use an environment variable or a secrets manager that encrypts at rest, and make sure any .env file is in .gitignore before you add the key. Never commit secrets, paste them into screenshots or support tickets, or hand them to unvetted third-party trackers. Scan old git history too.
Can someone drain my account without withdrawal permission?
Partly, yes, which surprises people. A key with trade permission can be abused through cross-trading: an attacker buys a thin market with your balance at an inflated price while selling from their own account. An IP allowlist blocks this by rejecting requests from any machine that is not yours, so pair both controls.
How often should I rotate API keys?
There is no magic interval, but rotate immediately after any suspected leak, when someone leaves a shared project, or when a key has lived in the same place as other exposed secrets. On a quiet solo setup, a periodic rotation every few months plus tight IP and permission settings is reasonable. The controls matter more than the calendar.
