Security model
Threat model and how the on-chain layer is protected.
Trusted boundaries
- VPS root account — holds the treasury private key in
/root/.katama-treasury.key(mode 600). Loss here = loss of signing capability for future batches; existing on-chain records are immutable. - Vercel project secrets — holds
CRON_SECRET,DATABASE_URL, Clerk keys. Loss here = ability to forge new blockchain_logs rows in the DB; the on-chain record still wins if it disagrees. - Postgres on VPS — source of all platform data. Cron uses local socket; Vercel uses public IP with password auth.
What attackers can NOT do, even with full Vercel access
- Sign a single transaction — the private key is not on Vercel.
- Force a rebroadcast — the cron is on the VPS and runs on its own schedule.
- Read past TX content beyond what is already public on Basescan.
What attackers CAN do with full Vercel access
- Read
blockchain_logscontents (no PII beyond user IDs). - Insert fake pending rows — but the VPS signer would broadcast them, creating a record that contradicts the off-chain DB and triggers monitoring.
- Disable the API by deploying broken code. Manual rollback is one Vercel CLI command.
Idempotency & replay protection
- DB layer: unique index on
(user_id, date)inblockchain_logs. - Contract layer:
batchKeyUsed[keccak256(userIdHash, date)]reverts on duplicate. - TX hash uniqueness: a TX hash that already settled another row is rejected by the txhash unique index.