Security

Security & Threat Model

Last updated: May 20, 2026

A trading bot platform holds the keys that move your money. We take that seriously. This page describes what we encrypt, what we don't see, what attacks we defend against, and how to disclose a vulnerability.

Sections

  1. Core security principles
  2. How we handle API keys
  3. Encryption — in transit & at rest
  4. Threat model
  5. AI Fix — what gets sent to Claude
  6. Infrastructure & vendors
  7. What you should do
  8. Responsible disclosure policy

1. Core security principles

Never take custody of funds.

We never hold, route, or have visibility into your trading capital. Your API keys talk directly to the exchange you choose; there is no WatchDog Bot wallet or escrow layer in the path. If we got fully compromised tomorrow, an attacker cannot steal a single dollar of your money — only your keys.

Minimize what we store.

We collect the smallest amount of data needed to run the service. API keys are encrypted. Code and logs are stored only for users who opted into cloud sync. Telemetry is opt-out. No third-party tracking.

Keys never appear in bot source.

Bots access credentials via wd.connection(name) at runtime — the SDK retrieves keys from the encrypted local store. Source code never has the secret in it, which means it can't accidentally end up in logs, in version control, or in a screenshot you share with us for debugging.

Reduce blast radius per bot.

Each bot runs in its own isolated Python venv. A malicious package in one bot's dependencies can't corrupt other bots or escape into the host shell. Each bot also has its own UUID; logs and state are scoped to that UUID end-to-end.

2. How we handle API keys

When you add an exchange API key in Settings → API Connections:

  1. The key + secret are encrypted in your local SQLite database using AES-256-GCM with a per-account key derived from your password (Argon2id KDF).
  2. If you've opted into cloud sync, an encrypted copy syncs to Supabase. Supabase sees only the ciphertext; the decryption key never leaves your local app instance.
  3. At runtime, your bot calls wd.connection("Kalshi"). The platform decrypts the key in-memory, passes it into the bot's process environment, and the bot uses it to authenticate with the exchange.
  4. The key is never logged. The platform's logging layer pattern-matches on common API key formats and redacts them before any log line is written.
  5. If you call repr(conn) by mistake, the Connection object returns a masked representation (e.g., Connection(name='Kalshi', api_key='ABC***...', ...)) — secrets are not exposed even by accident.

What we recommend you do at the exchange side:

3. Encryption

AssetIn transitAt rest
Account credentialsTLS 1.3Argon2id password hash; never plaintext
API keysTLS 1.3AES-256-GCM, per-account derived key
Bot source codeTLS 1.3Encrypted at rest in Supabase (cloud sync only)
Bot logsTLS 1.3Encrypted at rest in Supabase
Stripe billing dataTLS 1.3 (Stripe)PCI-DSS compliant at Stripe; we never touch full card numbers
BackupsEncrypted database snapshots, 30-day retention

4. Threat model

The threats we explicitly defend against:

ThreatDefense
Attacker gains access to our databaseAPI keys are AES-encrypted with a key derived from your password. Without your password, the ciphertext is useless.
Attacker intercepts API trafficTLS 1.3 with certificate pinning on the desktop client.
Malicious bot tries to exfiltrate other bots' dataEach bot runs in an isolated venv with restricted filesystem scope (cannot read other bots' state directories).
Malicious bot tries to escape the venvThe runtime doesn't run user code with elevated privileges. The OS sandbox (Windows AppContainer / macOS sandbox) is the final boundary.
Brute force on user passwordArgon2id with high cost parameters; rate-limited login attempts; mandatory 2FA on accounts that opt in.
SQL injection / XSS in dashboardParameterized queries throughout; React's automatic JSX escaping; CSP headers on dashboard pages.
Supply-chain attack via auto-installed depsAuto-install denylist for high-risk packages (setuptools, pip itself, etc.); package names sanity-checked before uv pip install; user-visible log when any new package is installed.
API key leaked via log filesLogger pattern-matches and redacts common key formats before write.

Threats we explicitly do not defend against (out of scope):

5. AI Fix — what gets sent to Claude

When you click "Fix with AI", the platform sends the following to Anthropic's Claude API:

What is explicitly not sent:

Full details: AI Fix Guide.

6. Infrastructure & vendors

The third-party services we use:

VendorPurposeWhat they see
SupabaseEncrypted databaseEncrypted ciphertext only; never decryption keys
RailwayWeb backend hostHTTP request metadata; no persistent storage of user data
StripePayment processingCard data (PCI compliant); never seen by us
AnthropicAI Fix LLM providerBot code + traceback per request; no training, no retention
Google WorkspaceEmail infrastructureStandard Gmail processing for support correspondence
GitHubCode hostingOur source code; no user data

All vendors are SOC 2 compliant. Geographic location: primarily US East (Supabase, Railway US West regions). EU/UK users: data may transfer to US under Standard Contractual Clauses (see Privacy Policy section 9).

7. What you should do

8. Responsible disclosure

Found a vulnerability? Tell us.

We don't currently operate a paid bug bounty, but we deeply appreciate responsible disclosure and credit reporters in our public changelog with their permission.

Response time: < 24 hours for initial acknowledgment, any day of the week, including weekends.

PGP key available on request. We accept reports in plain text or encrypted.

What we ask:

In scope:

Out of scope (please don't submit these unless they have unusual real-world impact):


Questions, audit requests, compliance docs?

For SOC 2 questions, DPA requests, vendor security questionnaires, or any other compliance need, email security@watchdogbot.cloud. We respond within 2 business days.