Exchange API Key Handling
Your exchange API keys are the most consequential credential you give VolatiCloud. They authorize trades on your behalf, and a misused key can cause real financial loss. This page documents exactly how we accept, store, use, and dispose of those keys — and what you should configure on the exchange side to make a leak of any kind effectively unexploitable.
The four pillars: withdrawal-disabled enforcement (we reject keys that can withdraw funds), AES-256-GCM at rest (field-level encryption before the database sees the value), memory-only at runtime (decrypted into runner pod memory, never written to disk or logged, zeroed on bot stop), and rotation guidance (rotate every 90 days with the procedure below).
The Withdrawal-Disabled Rule
VolatiCloud only accepts exchange API keys with the withdrawal permission disabled. When you save a connection, the backend probes the exchange's permission API; if the key has any withdrawal capability, the connection is rejected with this error message and we ask you to regenerate the key without it:
this API key has withdrawal capability enabled — VolatiCloud refuses keys that can withdraw funds; regenerate the key on the exchange with withdrawals disabled and reconnect
This is enforced in api/internal/exchange/permissions.go — it is not a UI hint or a recommendation, it's a hard backend check.
The blast-radius guarantee is concrete:
- If our infrastructure were fully compromised today, an attacker holding our database could attempt adverse trades but could not initiate withdrawals.
- The worst-case outcome is "what could an attacker do to my open positions" — not "all my funds are gone."
For comparison, the December 2022 3Commas breach (~100k API keys leaked, ~$22M stolen) was a withdrawal-enabled-key disaster. We do not store keys that can do that.
How Keys Are Stored at Rest
API keys are encrypted at the application layer with AES-256-GCM before being written to the database. The mechanism:
- Each value gets a fresh per-field nonce
- Ciphertext is base64-encoded and prefixed with
$vc_enc$v1$so the storage layer remains content-addressable - Encryption is applied via ENT hooks at write time and decryption via interceptors at read time — application code is unaware
Architectural decision: ADR-0026 — Field-Level Encryption. Implementation deep-dive: Encryption.
How Keys Are Used at Runtime
When a bot runs:
- The orchestrator decrypts the API key into the runner pod's process memory at job start.
- Freqtrade uses the key to connect to the exchange and place orders.
- The plaintext key is held in process memory only — never written to disk inside the runner pod, never emitted to logs, never serialized to a file.
- When the bot stops or the pod is reaped, the memory containing the key is overwritten before release.
This means even if an attacker could trigger a memory dump from a running runner pod they'd need to do so during a narrow window where the bot is actively running. The attack surface for stored credentials is minimized by keeping plaintext lifetime as short as the trading engine's process lifetime.
How to Lock Keys Down Further on Your Exchange
Even with our defenses, the strongest configuration is one where the key cannot be used outside our infrastructure even if it leaks. Configure the following on the exchange:
IP Allowlisting
Most major exchanges (Binance, Coinbase, Kraken, Bybit, OKX, KuCoin, Bitget, Gate.io) let you restrict an API key to specific source IPs. Lock your VolatiCloud-bound keys to our published runner egress IPs — see Egress IPs.
A leaked key with both withdrawals disabled and IP-restricted to our egress IPs is essentially useless to an attacker: they can't withdraw funds, and they can't even reach the exchange from outside our infrastructure to attempt adverse trades.
Permission Scoping
Beyond disabling withdrawals, disable any scope your strategy doesn't need:
- Spot-only strategies → disable Futures and Margin permissions
- Long-only strategies → disable Margin / Borrowing permissions
- Read-only research → create a separate key with only the Read scope for backtests against your account history
Smaller scope = smaller blast radius if anything goes wrong.
Rotation Cadence
We recommend rotating exchange API keys every 90 days. The procedure:
- Generate a new key on the exchange with withdrawals disabled, scoped to what your strategy needs, and IP-allowlisted to VolatiCloud's egress IPs.
- Update the connection in VolatiCloud — open the exchange in the dashboard, edit the connection, paste the new key and secret.
- Verify the next trade event uses the new key — VolatiCloud's audit log shows which key was used for each trade.
- Revoke the old key on the exchange.
Rotation is the single highest-leverage hardening action you can take. A 90-day rotation cadence means a leaked key has a bounded effective lifetime even if neither party noticed the leak.
What We Don't Do
- We don't store keys that can withdraw, ever — we reject them at add time.
- We don't share keys across organizations — every key belongs to exactly one org.
- We don't display the secret portion in the UI after you save it. The dashboard shows the last 4 characters of the API key for identification, but the secret and passphrase are never re-rendered.
- We don't ship API keys outside the runner pod — keys never leave the runner that uses them.
What's Coming — The Trust Feature Ladder
We're shipping a phased plan to put more of the trust boundary on your side instead of ours. Detailed plan: Threat Model — Roadmap. Highlights for API keys:
- Trust Tier 1 — Customer-supplied passphrase. Your organization's passphrase wraps the API key. The decryption key is derived from it via Argon2id and combined with our server-held key via envelope encryption. Server alone cannot decrypt; passphrase alone cannot decrypt. The Argon2id verifier itself is already implemented in
api/internal/passphrase/. - Trust Tier 2 — Passkey-bound E2EE. Strategy code and exchange keys are encrypted in your browser with a wrapping key bound to your hardware passkey. We mathematically cannot decrypt without your authorization.
- Trust Tier 3 — Bring Your Own Key (BYOK). Your AWS / GCP / Azure / Vault holds the wrapping key. You can revoke our decrypt access in your IAM with one policy change.
Related guides
- Encryption — Details of the at-rest encryption, key management, and audit logs.
- Threat Model — Actors, defenses, and the full trust roadmap.
- Egress IPs — Runner egress IPs to allowlist on your exchange.
- Exchanges Overview — How to add a connection through the wizard.