Skip to content

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)

SecretTypeOwnerRotation cadenceRotation difficulty
Devnet program keypairsSolana keypairProtocol teamOn compromise onlyMedium — program ID changes
Mainnet program keypairsSolana keypairProtocol team (cold storage)Never (frozen post-launch)Catastrophic — program ID changes
Solana wallet keypair (upgrade authority)Solana keypairProtocol teamQuarterly + on operator turnoverMedium — re-authorize via set-upgrade-authority
Helius API keyAPI keyWorkspaceQuarterly + on suspected leakLow — rotate in Helius dashboard, redeploy Workers
Webhook HMAC secret (per merchant endpoint)random bytes (32)Merchant + dashboardDual-secret rotation supportedLow — D1 column update
Resend API keyAPI keyWorkspaceQuarterlyLow — rotate in Resend, redeploy
Turnstile site + secretAPI keyWorkspaceAnnuallyLow — rotate in Cloudflare, redeploy
D1 binding tokensCloudflare credentialCloudflare account ownerOn operator turnoverLow — handled by wrangler
Better Auth session signing keyrandom bytes (64)Dashboard worker envOn compromiseMedium — invalidates active sessions
Arcium cluster credentialsArcium account credsProtocol teamOn Arcium-side rotationMedium — coordinated with Arcium
GitHub deploy keys / fine-grained PATsGitHub tokenWorkspaceQuarterly + on operator turnoverLow — generate new, replace in CI
Cloudflare API token (deploy CI)Cloudflare credentialWorkspaceQuarterlyLow

Where Secrets Live

LocationStores
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 dashboardArcium 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

  1. Generate a new key in the Helius dashboard.
  2. Update each consumer Worker:
    sh
    cd <worker-dir>
    bunx wrangler secret put HELIUS_API_KEY
  3. Redeploy the worker (bunx wrangler deploy).
  4. Verify via the worker logs that the new key is in use.
  5. 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.

  1. Merchant requests rotation via dashboard UI (or admin triggers it).
  2. Dashboard generates a new secret, stores it in hmac_secret_secondary.
  3. Both secrets accept inbound deliveries for the configured window (default 24h).
  4. Merchant updates their verifier to the new secret.
  5. 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

  1. Generate a new keypair, back it up three ways before exposing it.
  2. Run the existing authority:
    sh
    solana program set-upgrade-authority <PROGRAM_ID> --new-upgrade-authority <NEW_PUBKEY>
  3. Verify with solana program show <PROGRAM_ID>.
  4. Update internal-wiki/operations/environments.md with the new pubkey.
  5. 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.

  1. Generate 64 random bytes.
  2. bunx wrangler secret put BETTER_AUTH_SECRET for the dashboard worker (and the Bun-on-Railway server's env).
  3. Redeploy.
  4. 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.

  1. Do not delete anything. Preserve forensic state.
  2. Immediately page the protocol team (use the on-call escalation tree in Incident Response → Escalation).
  3. Pause the protocol via pause_protocol instruction signed by the current admin (if not yet rotated).
  4. Initiate the ceremony to rotate to a fresh upgrade authority from cold storage.
  5. Communicate transparently to merchants — silence here is worse than disclosure.

Severity 1 — Helius / Resend / Cloudflare API tokens

  1. Rotate the secret immediately (see procedures above).
  2. Audit logs for unauthorized use during the leak window.
  3. File an internal post-mortem.

Severity 2 — webhook HMAC secret leaked (single merchant)

  1. Trigger dual-secret rotation.
  2. Notify the affected merchant.
  3. No protocol-wide impact.

Severity 3 — operator dev keypair leaked

  1. Move funds out of the affected wallet.
  2. Generate a new operator keypair.
  3. Update local ~/.config/solana/id.json.
  4. If the keypair was an upgrade authority, also follow the upgrade-authority rotation.

Secret Hygiene Rules

  • Never commit .env files. Every repo's .gitignore must include .env*.
  • Use wrangler secret put NAME for Worker secrets — never put them in wrangler.toml.
  • Bun auto-loads .env files; do not use dotenv. Local .env.example files document required variables without values.
  • Pre-commit hooks should run git-secrets or 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 put is leaking by virtue of typing the secret. Use wrangler 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

WhatWhere
Who rotated which secret whenAppend to a row in .planning/security-rotations.log (one line per rotation: timestamp, secret name, operator)
Which Worker deployed which secret versionwrangler deployments list per Worker
Who upgraded the protocolOn-chain — solana program show <PROGRAM_ID> shows current authority

Internal knowledge base for the Vela Labs workspace.