Fix guides

Your host was breached (Railway): how to rotate every secret, in the right order

Railway says customer environment variables may have been decrypted. A priority-ordered checklist for vibe-coded apps: rotate Stripe, database, Supabase, and AI keys at the provider, revoke the old ones, check the logs, and keep shipping while deploys are paused.

What you are seeing

Why it happens

  1. Environment variables are where every secret in a deployed app ends up: payment keys, database URLs, Supabase service keys, AI keys. If the store holding them is exposed, all of them are exposed at once.
  2. Changing the value in Railway does nothing to the old key. The old key stays valid at Stripe, Supabase, or OpenAI until you revoke it there.
  3. Containers read variables only at startup, so a new value takes effect only after a redeploy. That is why paused builds hurt.
  4. Not every secret is equally dangerous. A Stripe secret key can move money, a database password can read or delete every user's data, and an AI key can run up a bill. Rotating in the wrong order wastes the hours that matter.

How to fix it

1. List every secret first

Open each Railway service's Variables tab (and Project Settings for shared variables) and write down every key, password, token, and connection string, plus which provider issued it. Include anything that also lives outside Railway: local .env files, CI secrets, and other hosts. This list is your checklist for the rest of the steps.

2. Rotate in this order: money first, then data, then AI and everything else

  1. Money-moving keys: Stripe secret and restricted keys, webhook signing secrets, PayPal or other payment keys, crypto or wallet keys.
  2. Database credentials: Postgres, MySQL, MongoDB, and Redis passwords and connection URLs, Supabase database password and service_role or secret key.
  3. AI and API keys: OpenAI, Anthropic, OpenRouter, Grok, email, SMS, and storage keys.
  4. Auth and app secrets: JWT or session signing secrets, OAuth client secrets, GitHub or registry tokens.

3. Rotate at the provider, then revoke the old key there

For each secret: create the new key in the provider's dashboard, put it in Railway (or your temporary host), redeploy, and confirm requests succeed with the new key. Then revoke or delete the old key at the provider. Stripe's Rotate key option lets you choose an expiry: pick Now for a confirmed leak, or a short window if you need time to redeploy. If you cannot deploy yet, revoking the money and database keys now is usually worth a short outage.

4. Check each provider's logs for use of the old key

5. Supabase: reset the database password

In the Supabase Dashboard, open Project Settings, then Database, and reset the database password. This invalidates the old password for direct and pooler connections. Update DATABASE_URL wherever it is used, then redeploy.

6. Supabase: replace the service_role key and the JWT secret

Go to Settings, then API Keys, and create the new publishable and secret keys (they work alongside the legacy anon and service_role keys). Swap service_role for the secret key (sb_secret_...) in backend code, and anon for the publishable key in the frontend. Once nothing uses the legacy keys, deactivate them on the same page. If your legacy JWT secret was in Railway, migrate to JWT Signing Keys and use Rotate Keys, then revoke the old one. Supabase's docs say to disable the legacy anon and service_role keys before revoking the legacy JWT secret, because those keys are JWTs signed with it.

7. Supabase: if the project is paused

A paused Free project's database is not serving connections, so a leaked password is not usable until you restore it. Before restoring, make sure nothing will reconnect with the old string. Then restore and immediately reset the database password and rotate the keys as above. Keep the gap between restoring and resetting to a minute or two.

8. While Railway deploys are paused: keep shipping somewhere else

Your repo is not tied to Railway. Short term you can deploy the same repo with the new keys on Render or Fly.io (long-running servers and workers), or Vercel or Netlify (Next.js and static frontends), and point your domain there. Move it back later if you want. Per Railway's status page, builds came back for paid tiers first (Enterprise, then Pro), so check which tier you are on before you migrate anything.

9. Handle what Railway already reset

Railway regenerated every storage bucket's ACCESS_KEY_ID and SECRET_ACCESS_KEY and removed the GitHub tokens it held. Services pick up new bucket credentials on their next redeploy. Reconnect GitHub yourself, and revoke any GitHub tokens you had stored as registry credentials, because Railway says those still work on GitHub until you revoke them. Railway API tokens were also invalidated, so create new ones for any CI that uses the Railway API.

How to know it is fixed

Every line on your list from step 1 has a new value deployed and the old one revoked at the provider. Each old key fails if you try it (Stripe returns 401, the database refuses the old password), the new keys show traffic in their request logs, and the provider logs show nothing you cannot explain since October 21. Sources: Railway's disclosure, Railway status, Railway's Stripe guide, Railway's bucket and GitHub guide, Supabase API keys, and Supabase JWT signing keys.