Coldtill Get Coldtill

Security

Paste into Claude Code, Codex, Cursor or your favourite coding agent. View Markdown

This guide explains how Coldtill protects money and what you, as the operator, need to do to keep it that way. The threat model lists threats and mitigations in detail, and the October 2026 audit report lists what was found and fixed.

What's at risk, and what isn't

Funds Who can move them
Customer deposits (EVM, Solana) Anyone can trigger a sweep, but it can only go to your cold wallet. The server can't change that
Bitcoin deposits Only you: they land directly in your own wallet, derived from your xpub
Your cold wallets Only you. Coldtill never sees those keys
Hot wallets The sweeper and payouts processes, after decrypting the key with your passphrase

A complete server compromise can, at worst, spend the hot wallets' balances and tamper with payment records (for example marking an unpaid order as paid). It cannot redirect deposits. Keep the hot float small, and cross-check large orders against the chain before shipping.

Operator checklist

Before going live:

  • Run on a dedicated server or VM, kept up to date (sudo apt update && sudo apt upgrade).
  • Use an https:// site URL. Caddy obtains the certificate.
  • Only ports 80 and 443 are open (sudo ufw allow 80,443/tcp && sudo ufw enable). Postgres is not published.
  • Every user has two-factor authentication. Give project_admin only to people trusted to approve payouts.
  • Use your own or paid RPC nodes for each enabled network, ideally more than one provider. See Nodes.
  • Payout limits: a low auto-approve amount, plus hourly and daily limits.
  • The hot wallets hold about a week of gas and payouts, no more.
  • deploy/.env and deploy/secrets/ are backed up offline, and the database is backed up daily.
  • SMTP works: approve a small test payout end to end.
  • Your webhook handler uses X-Coldtill-Signature-V2 (or the SDK's verifyWebhookRequest).
  • For extra protection, run without a stored passphrase (see Install).

Accounts and sessions

  • Passwords are hashed with Argon2id (64 MiB, 3 passes). At most four hashes run at once, so login floods can't exhaust memory.
  • Login is rate limited per IP address and per email: 10 attempts a minute.
  • Two-factor (TOTP) is needed to log in once enabled, and a fresh code is needed for sensitive actions. Each code works once. Five wrong codes lock two-factor checks for that user for 15 minutes; the lock is held in memory, so it resets if the api process restarts.
  • Sessions use HttpOnly, Secure and SameSite=Strict cookies. State-changing requests must come from the same origin and be JSON.

Actions that need a fresh two-factor code include:

  • creating, approving or resolving payouts;
  • editing the address book or payout limits;
  • creating API keys;
  • adding RPC nodes or lowering confirmation counts;
  • assigning hot wallets, setting up deposit wallets;
  • changing auto-convert settings.

Roles

Role Can
root Everything, including managing admins
admin (global) Manage users, hot wallets, nodes and networks, and all projects
member (global) Only the projects they're added to, with that project's role
project_admin Project settings, API keys, webhooks, payouts and approvals
developer Create payments and view everything in the project
read_only View only

Hot wallets

  • Keys are encrypted with age. Only the sweeper and payouts containers get the identity file and passphrase; the api process can encrypt imported keys but never decrypt them.
  • Transactions are signed and stored before broadcast, so a crash can't produce a second payment.
  • Nonces are reserved under a database lock; gaps are filled automatically.
  • Payouts Coldtill can't account for become needs-review instead of guessing. See Payouts.

Nodes

Coldtill doesn't trust RPC nodes with keys, but it does trust them to report deposits honestly. A malicious node could report a deposit that never happened. Mitigations:

  • Use nodes you run or pay for, not the public defaults. Add several, from different providers.
  • Bitcoin deposits are only orphaned when every node agrees the transaction is gone.
  • EVM chain IDs are signed into every transaction, and the Solana genesis hash is pinned, so a node on the wrong network can't trick the signers.
  • For large orders, check the deposit on a block explorer before shipping.

Node URLs often carry API keys. They're never shown in error messages and adding a node needs two-factor.

Webhooks

  • Each endpoint has its own secret, sealed in the database with the server secret.
  • The v2 signature covers a timestamp, so receivers can reject replays.
  • Coldtill refuses to connect to private and reserved addresses on mainnet (checked at connect time, so DNS rebinding doesn't help) and doesn't follow redirects.

Web security

  • Strict content security policy on the dashboard and checkout. Neither can be framed.
  • Uploaded logos are re-encoded as PNG and served with their own sandboxing policy. SVG is refused.
  • The checkout only shows data for its own payment and is rate limited.

Updates and vulnerability reports