Skip to content

Security Hardening

Production checklist for deploying PayWarden securely.

Pre-launch checklist

Secrets

  • [ ] VAULT_KEY is 32 random bytes (openssl rand -hex 32), not a human-readable password
  • [ ] VAULT_KEY is backed up offline in a secure location (password manager, HSM, or printed and locked)
  • [ ] API_KEY is unique and not reused from development
  • [ ] .env is not committed to git (check .gitignore)
  • [ ] Mnemonic phrase is written down and stored offline — not in any digital system

Network

  • [ ] PayWarden runs behind a reverse proxy (Nginx, Caddy, or Cloudflare Tunnel)
  • [ ] Direct port 3000 is not exposed to the internet
  • [ ] HTTPS is enforced — all webhook URLs use https://
  • [ ] Cloudflare or similar DDoS protection is enabled

Server

  • [ ] Server has a firewall — only ports 80, 443, and 22 are open
  • [ ] SSH uses key-based auth only (no password auth)
  • [ ] Automatic security updates are enabled
  • [ ] Server is not running other public-facing services on the same machine

Docker

  • [ ] Containers run as non-root users
  • [ ] vault.enc is mounted as a volume outside the container image
  • [ ] Docker socket is not exposed to the app container
  • [ ] restart: always is set for production

Key rotation

Rotating VAULT_KEY

If you suspect VAULT_KEY is compromised:

bash
# 1. Generate a new key
openssl rand -hex 32   # → NEW_VAULT_KEY

# 2. Decrypt the vault with the old key
# (requires vault-rotate script — coming in v1.1)

# 3. Re-encrypt with the new key

# 4. Update VAULT_KEY in .env

# 5. Restart the app
docker compose restart app

WARNING

Never change VAULT_KEY without re-encrypting vault.enc. If VAULT_KEY and vault.enc are out of sync, the app will fail to start.

Rotating API keys

API keys can be rotated without downtime:

  1. Create a new API key via the admin dashboard
  2. Update API_KEY in your backend's environment
  3. Delete the old API key once confirmed working

Rate limiting

PayWarden applies rate limiting to all endpoints:

EndpointLimit
POST /payments60 req/min per API key
GET /payments120 req/min per API key
GET /checkout/:id/status60 req/min per IP
POST /admin/login5 req/min per IP

For higher limits, configure a Redis-backed rate limiter in front of the gateway.


Webhook security

  • Always verify the X-PayWarden-Signature header before processing webhooks
  • Respond within 5 seconds — use a queue if processing takes longer
  • Use X-Idempotency-Key to deduplicate retried deliveries
  • Your webhook endpoint should be HTTPS only

Monitoring

Set up alerts for:

  • App container health check failures
  • PostgreSQL disk usage > 80%
  • Failed webhook deliveries (check admin dashboard)
  • Hot wallet TRX balance drops below GAS_LOW_THRESHOLD
  • Unusual order volume spikes

Incident response

If you suspect a breach:

  1. Immediately rotate API_KEY — this cuts off attacker API access
  2. Check order_events table for unauthorized orders
  3. Check admin logs for unauthorized login attempts
  4. If VAULT_KEY may be compromised, rotate it (see above)
  5. If the mnemonic is compromised, sweep all funds to a new wallet immediately

The mnemonic is the ultimate key to all funds. Protecting it is the highest priority.

Released under the BSL 1.1 License.