# Security

This guide explains how Coldtill protects money and what you, as the operator, need to do to keep it that
way. The [threat model](https://coldtill.com/docs/threat-model.md) 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](#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](https://coldtill.com/docs/install.md#running-without-a-stored-passphrase)).

## 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](https://age-encryption.org). 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](https://coldtill.com/docs/payouts.md#needs-review).

## 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

- Server admins see a banner when a newer version exists, and a red one when a security advisory affects the running
  version. Critical and high advisories are also emailed. See [Updates and advisories](https://coldtill.com/docs/updates.md).
- Advisories are published at [coldtill.com/security](https://coldtill.com/security). Security fixes are free to
  install even after your update year ends.
- Upgrade as described in [Install](https://coldtill.com/docs/install.md#upgrades).
- CI runs `govulncheck`, `gosec`, gitleaks and `npm audit` on every push. To run them yourself, see
  How to get Coldtill audited.
- Report vulnerabilities privately to security@coldtill.com (see [coldtill.com/.well-known/security.txt](https://coldtill.com/.well-known/security.txt)), not in public issues.

---

Source: https://coldtill.com/docs/security/ · All Coldtill docs: https://coldtill.com/llms.txt
