Appearance
Secrets Management
How VelaPay handles every secret in the workspace — what they are, where they live, how to rotate them, and what to do if one leaks. The wiki never stores secret values; it stores secret names and ownership.
For the canonical inventory of secret names, see Environment Registry → Secret Registry. This page is the lifecycle companion: rotation cadence, rotation procedure, compromise response.
Secret Inventory (lifecycle view)
| Secret | Type | Owner | Rotation cadence | Rotation difficulty |
|---|---|---|---|---|
| Devnet program keypairs | Solana keypair | Protocol team | On compromise only | Medium — program ID changes |
| Mainnet program keypairs | Solana keypair | Protocol team (cold storage) | Never (frozen post-launch) | Catastrophic — program ID changes |
| Solana wallet keypair (upgrade authority) | Solana keypair | Protocol team | Quarterly + on operator turnover | Medium — re-authorize via set-upgrade-authority |
| Helius API key | API key | Workspace | Quarterly + on suspected leak | Low — rotate in Helius dashboard, redeploy Workers |
| Webhook HMAC secret (per merchant endpoint) | random bytes (32) | Merchant + dashboard | Dual-secret rotation supported | Low — D1 column update |
| Resend API key | API key | Workspace | Quarterly | Low — rotate in Resend, redeploy |
| Turnstile site + secret | API key | Workspace | Annually | Low — rotate in Cloudflare, redeploy |
| D1 binding tokens | Cloudflare credential | Cloudflare account owner | On operator turnover | Low — handled by wrangler |
| Better Auth session signing key | random bytes (64) | Dashboard worker env | On compromise | Medium — invalidates active sessions |
| Arcium cluster credentials | Arcium account creds | Protocol team | On Arcium-side rotation | Medium — coordinated with Arcium |
| GitHub deploy keys / fine-grained PATs | GitHub token | Workspace | Quarterly + on operator turnover | Low — generate new, replace in CI |
| Cloudflare API token (deploy CI) | Cloudflare credential | Workspace | Quarterly | Low |
Where Secrets Live
| Location | Stores |
|---|---|
wrangler secret put NAME (per Worker) | Helius keys, Resend, Turnstile, Better Auth signing key, Arcium creds |
~/.config/solana/id.json (operator machine) | Operator wallet keypair |
~/.config/velapay/keys/devnet/ (operator machine) | Devnet program keypairs |
| Cold storage (hardware-backed, three locations) | Mainnet program keypairs |
D1 (webhook_endpoints.hmac_secret_primary, …_secondary) | Webhook HMAC secrets per merchant |
| GitHub secrets (per-repo) | Deploy CI tokens |
| Arcium dashboard | Arcium credentials |
The wiki, .env files committed to git, public docs, and chat must never contain secret values. If you find one, treat it as a leak (see Compromise Response below).
Rotation Procedure (per-secret)
Helius API key
- Generate a new key in the Helius dashboard.
- Update each consumer Worker:sh
cd <worker-dir> bunx wrangler secret put HELIUS_API_KEY - Redeploy the worker (
bunx wrangler deploy). - Verify via the worker logs that the new key is in use.
- Revoke the old key in the Helius dashboard.
Webhook HMAC secret (per merchant endpoint)
@velapay/webhook supports dual-secret rotation. Both secrets validate during a rotation window so deliveries don't fail.
- Merchant requests rotation via dashboard UI (or admin triggers it).
- Dashboard generates a new secret, stores it in
hmac_secret_secondary. - Both secrets accept inbound deliveries for the configured window (default 24h).
- Merchant updates their verifier to the new secret.
- After the window, dashboard promotes secondary to primary and clears the old.
This is the only rotation flow that doesn't require redeploying Workers — D1 is the source of truth.
Solana upgrade authority
- Generate a new keypair, back it up three ways before exposing it.
- Run the existing authority:sh
solana program set-upgrade-authority <PROGRAM_ID> --new-upgrade-authority <NEW_PUBKEY> - Verify with
solana program show <PROGRAM_ID>. - Update
internal-wiki/operations/environments.mdwith the new pubkey. - Securely retire the old keypair (move to cold archive — do not delete).
Better Auth signing key
This is destructive — rotating invalidates all active sessions, forcing every merchant to re-login. Coordinate with merchants before rotation unless responding to a confirmed leak.
- Generate 64 random bytes.
bunx wrangler secret put BETTER_AUTH_SECRETfor the dashboard worker (and the Bun-on-Railway server's env).- Redeploy.
- Communicate the forced logout to merchants.
Compromise Response
If a secret is exposed (committed to git, posted in chat, found in logs, suspected leaked):
Severity 0 — mainnet program keypair, mainnet upgrade authority
This is the highest-severity workspace incident.
- Do not delete anything. Preserve forensic state.
- Immediately page the protocol team (use the on-call escalation tree in Incident Response → Escalation).
- Pause the protocol via
pause_protocolinstruction signed by the current admin (if not yet rotated). - Initiate the ceremony to rotate to a fresh upgrade authority from cold storage.
- Communicate transparently to merchants — silence here is worse than disclosure.
Severity 1 — Helius / Resend / Cloudflare API tokens
- Rotate the secret immediately (see procedures above).
- Audit logs for unauthorized use during the leak window.
- File an internal post-mortem.
Severity 2 — webhook HMAC secret leaked (single merchant)
- Trigger dual-secret rotation.
- Notify the affected merchant.
- No protocol-wide impact.
Severity 3 — operator dev keypair leaked
- Move funds out of the affected wallet.
- Generate a new operator keypair.
- Update local
~/.config/solana/id.json. - If the keypair was an upgrade authority, also follow the upgrade-authority rotation.
Secret Hygiene Rules
- Never commit
.envfiles. Every repo's.gitignoremust include.env*. - Use
wrangler secret put NAMEfor Worker secrets — never put them inwrangler.toml. - Bun auto-loads
.envfiles; do not usedotenv. Local.env.examplefiles document required variables without values. - Pre-commit hooks should run
git-secretsor equivalent for everyone on the team. (Operators: confirm with the workspace owner if your machine doesn't have it set up.) - Shared screens: assume any
wrangler secret putis leaking by virtue of typing the secret. Usewrangler secret put NAME --and paste from a password manager. - Logs: never log a full secret. Log a hash or the last 4 chars at most.
Audit Trail
| What | Where |
|---|---|
| Who rotated which secret when | Append to a row in .planning/security-rotations.log (one line per rotation: timestamp, secret name, operator) |
| Which Worker deployed which secret version | wrangler deployments list per Worker |
| Who upgraded the protocol | On-chain — solana program show <PROGRAM_ID> shows current authority |
Related
- Inventory: Environment Registry → Secret Registry
- Mainnet ceremony: Protocol Deployment Runbook
- Incident escalation: Incident Response →