BANGER
Product status: Banger’s public beta is paper-only. References to live execution are future-looking. Venue rules and legal claims can change; verify current primary sources for your jurisdiction.
2026-08-03 · 6 min read · facts as of 2026-08-03

Secrets Management for Trading-Bot API Keys

A venue API key for Polymarket or Kalshi is not a password you can reset with an email link. It signs orders and, depending on scope, can move money. Treat it like account credentials, because that is what it is. Stripe puts it plainly for its own keys, and the logic carries straight over to trading venues.

This post covers the four things that actually matter for a trading bot: keeping keys out of source control, isolating them per environment, encrypting them at rest, and scoping them to the minimum permission the strategy needs. It closes with how a bring-your-own-key runtime like Banger fits the model without adding a new place for keys to leak.

Rule zero: never commit the key

The single most common way credentials leak is git. A developer adds a .env file or hardcodes a key during a debugging session and commits it. Once that reaches a public repo, automated scanners find it fast.

The scale is not theoretical. The 2024 GitGuardian State of Secrets Sprawl report (covering 2023 data) found over 12.8 million new secret occurrences on public GitHub in a single year, and notes the real total across private repos and other platforms is far higher. Palo Alto Networks Unit 42 has documented that attackers routinely harvest credentials from public repos within five minutes of exposure.

The prevention is boring and effective. Add your secrets file to .gitignore before you ever write a real value into it, and commit a template instead.

# .gitignore
.env
.env.*
!.env.example

# .env.example  (committed, no real values)
KALSHI_API_KEY_ID=
KALSHI_PRIVATE_KEY_PATH=
POLYMARKET_API_KEY=
POLYMARKET_API_SECRET=
POLYMARKET_API_PASSPHRASE=

A committed .env.example lets a teammate know which variables are required without exposing any real value. Note the gotcha: dotenv-style files are plain text. python-dotenv does not encrypt anything, so the .env file itself is only as safe as the machine and the .gitignore protecting it.

If a key does hit a repo, treat it as compromised the instant it lands. GitHub's own guidance is that removing the secret, pushing a new commit, or deleting the repo do not prevent exploitation. You have to revoke and reissue. Enable push protection and secret scanning so a known key format is blocked before the commit ever reaches a repository.

Isolate environments

Load keys from the process environment at startup, not from source. In Python that is os.getenv, optionally hydrated from a .env file in development by python-dotenv. Keep separate credentials per environment so a mistake in testing cannot touch a live account.

In CI/CD, do not pass secrets in a committed .env. Inject them at runtime through the platform's secret store (GitHub Actions secrets, GitLab CI/CD variables, a cloud secrets manager) so they never persist in a file on disk.

Encrypt at rest, and prefer a real store

A plaintext .env in your home directory is fine for a solo dev on a locked machine, and honest about its limits. Anything beyond that should use a system that provides encrypted storage plus access controls: a KMS, HashiCorp Vault, AWS Secrets Manager, or an equivalent. Stripe recommends copying a freshly created secret key straight into a KMS that handles it with encryption and access controls, and the same pattern applies to venue keys.

The deeper point from OWASP is that secrets fail as a lifecycle, not as a storage choice. Ownership, access scoping, rotation, revocation, and auditability are what keep keys governable. A vault that no one rotates is just an encrypted way to hold a stale credential.

Least privilege and rotation

Scope every key to the narrowest permission the strategy needs. If the venue lets you create a key that can trade but not withdraw, use it. If it supports IP allowlists, pin the key to the box the bot runs on. The goal is to shrink the blast radius: a leaked trade-only key locked to one IP is a far smaller problem than an unrestricted one.

Rotate on a schedule, not just after an incident. Common guidance is a maximum lifetime around 90 days for long-lived API keys, with automated rotation because manual rotation does not happen consistently. Rotation under incident pressure is where mistakes get made, so practice it in a staging setup and document the revocation procedure for each venue before you need it. And never log the key. Redact credentials out of request and response logging so they do not end up in a log aggregator you forgot to lock down.

Where a bring-your-own-key runtime fits

Banger runs your strategy against your own venue accounts. It never custodies funds and never holds your keys on a server. You bring your own Polymarket or Kalshi keys, they stay in your environment, and the runtime reads them from the process at execution time. That keeps the trust boundary where it belongs: on your machine, under your .gitignore, in your vault, not in a third party's database that becomes a single juicy target.

The practical workflow lines up with everything above. Paper-trade first against the live order book, keep the live key out of the process until the strategy behaves, then run it with a declarative risk envelope: per-trade cap, daily loss stop, max open positions, and a kill switch. A leaked key is a security failure. An unbounded strategy with a valid key is a financial one, and the risk envelope is your backstop for the second class of problem.

# keys come from the environment, never from the file you commit
pip install bangertrades

export KALSHI_API_KEY_ID=...        # loaded at runtime, gitignored source
banger run strategy.py --paper      # validate against the live book first
# then, once it behaves, run live with your risk envelope

The short version

Sources

Keep reading

Run your first strategy free

Paper-trade on Polymarket and Kalshi market data without venue keys.

Start free