How to rotate app secrets after a platform breach (Railway, Zeabur)
For people whose app has a backend, API or worker on Railway or Zeabur. Facts checked 24 October 2026; each step ends as detected, unknown or confirmed by owner evidence.
Published Last updated
If your app's backend stored secrets in Railway or Zeabur, replace every one of them this week, even if no email has arrived. Create a new key at the service that issued it, put it in your host, redeploy, revoke the old key, then read that service's logs. Both platforms published their own breach reports in October 2026, and neither had a final scope at our check.
Do I need to rotate if my app used Railway or Zeabur?
A mobile app built with React Native and Expo usually talks to a backend: an API, a worker, a database. If that backend ran on either platform, the variables you gave it (database passwords, payment keys, AI provider keys, session secrets) sat in the platform's store. The app on the phone is not the problem here. The copies of your keys are.
Facts below come from each vendor's own pages, read on 24 October 2026. They are vendor statements, not independent forensics.
| Platform | What the vendor says | What it asks of you | Dates |
|---|---|---|---|
| Railway | An unauthorized party may have accessed encrypted environment variables and, for some, obtained the decrypted contents. Its preliminary report says user source code access is not ruled out until the final forensic report. | Roll all environment variables and private registry credentials, remove public database access, and review GitHub and registry audit logs. | Disclosure 21 Oct 2026. API tokens invalidated 22 Oct, 04:39 UTC. Preliminary report listed on its status page 23 Oct. |
| Zeabur | A second incident on 14 and 15 Oct 2026. The report says environment-variable records from its platform database were taken, and that how the attacker got the first credentials cannot be confirmed yet. | Replace every credential in your variables, recreate access tokens, and change database passwords inside the databases. | Report 19 Oct 2026, marked preliminary. Shutdown announced 17 Oct, with servers stopping 1 to 31 Dec. |
Read the vendor pages yourself: Railway's disclosure, its preliminary report and Zeabur's incident report. Zeabur also announced a wind-down, a separate event from the breach.
Neither vendor had published a per-customer list at our check, so "I got no email" is unknown, not confirmed. Treat every secret stored on the platform before the dates above as exposed. This page does not repeat any victim count, because the vendors' own numbers were still moving.
If you want the longer, host-neutral version of this advice, the rotate secrets after a breach guide on red.run.cloud covers it for site owners. This page covers what is different when the thing you ship is an app.
In what order should I rotate?
Start with the keys that can lose you money or let someone act as your backend, and finish with the ones that only read. The flow for each single secret is the same:
| Order | Secret | Where the old one is revoked | What done looks like |
|---|---|---|---|
| 1 | Keys that sign transactions or hold funds | On the wallet or chain side. Move the funds first; a new key does not recover anything already moved. | Funds sit under a key never stored online. |
| 2 | Payment keys (sk_live_, rk_live_) | Stripe Dashboard, API keys page. Rotating gives a replacement at once; choose expiry "Now" for a key you think is exposed. | Old key shows expired and its request log reads zero. |
| 3 | AI provider keys | The provider's console. Railway says it asked providers to revoke keys, so an old key may already fail with an auth error. Still create a new one. | New key in use, old key absent from the console. |
| 4 | Database passwords and connection strings | Inside the database itself. Zeabur says editing an environment variable does not change the password. | Login with the new password works, the old one is refused. |
| 5 | Backend and auth keys (Supabase secret or legacy service_role, JWT and session secrets) | Supabase: create a replacement, update every use, then delete a secret key or deactivate a legacy one. A service role key skips row level security, so do this early. | Dashboard shows only the new key active. Expect users to sign in again after a signing-secret change. |
| 6 | Source and registry tokens | GitHub settings: revoke the old token, create a new one with only the scope needed, reconnect the platform. | Old token gone from GitHub; audit log reviewed. |
| 7 | Platform API and access tokens | Railway invalidated its API tokens on 22 Oct, and Zeabur asks you to sign in again and recreate access tokens. Create new ones for your CLI and CI. | CI runs green with the new token. |
Fix the cause before the key
Supabase's guidance is to fix the root cause of a leak before rotating anything, or the new key can leak the same way. Here the cause was on the platform side, so the useful check on your side is whether a second copy of the secret sits somewhere else, such as a committed file or a build log.
How do I rotate without breaking the app?
Rotation breaks things when the new value reaches only half the places that use it. Work in this sequence for each secret.
- Search your project for the variable name. Because you can download your code or connect your own repository, this is a plain text search across files you hold, including workers and scheduled jobs.
- Create the new value at the issuer. Stripe keeps both keys working for up to 7 days when you rotate in the Dashboard, which gives time to watch the old key's request log fall to zero before expiring it. If you suspect misuse, skip the grace period.
- Update the platform variable, or the replacement platform's, and redeploy. Railway's bucket credentials were reset for every bucket, and its reset guide says services that reference them need a redeploy.
- Revoke the old value. Per GitHub's remediation guide, revoking at the provider is the most important step; deleting the text from code does not stop a copy that was already taken.
What if a key is inside the app itself?
Expo writes every variable that starts with EXPO_PUBLIC_ into the bundle, and Expo's docs say not to put secrets there. EAS offers secret-visibility variables for build jobs, and the same page says anything included in client-side code should be treated as public. If a secret ever shipped that way, rotating it on the server is the first half. The second half is a new build, because installed copies keep the old value until users update.
A Supabase publishable (or legacy anon) key is meant to be public and relies on row level security. Do not rotate it out of panic; check your policies instead, as in the 15-minute app check.
Afterwards, the OWASP Secrets Management Cheat Sheet is the plain reference for keeping the next rotation short: one inventory, least privilege per key, and a rotation you can run on a bad day.
How do I tell whether a key was used?
Rotation closes the door. The logs tell you whether anyone walked through it first. Read them at the issuer, not on the platform:
- Stripe: the request log for each key, opened from the API keys page.
- GitHub and registries: the account audit log and app access list, which Railway's preliminary report asks you to review.
- Cloud and AI providers: usage, billing and sign-in history from the exposure window. For Railway that is 20 October 2026 (its report puts the unauthorized activity from 20 October to early 22 October UTC); for Zeabur dedicated servers the report suggests sign-in history back to 1 September 2026.
- Your own database: connections from addresses you do not run.
Write down what you read and the date range. A quiet log is unknown until you have confirmed the logging was on. If something looks wrong, the website incident response playbook has the next steps for a live site.
Where do you stand?
Mark each item. Everything starts as unknown. Move one to confirmed only when you hold the evidence listed under it.
Your rotation check
- Detected: You found the problem.
- Unknown: Not checked yet, or the check could not tell.
- Confirmed by owner evidence: You checked and kept the proof.
Your answers stay in this browser tab. Nothing is saved or sent.
Frequently asked questions
My app is on the App Store. Do I need to resubmit it?
Only if a secret was compiled into the app. Values that start with EXPO_PUBLIC_ are written into the JavaScript bundle, so a key you used there is readable by anyone with the app and a new build is needed. Keys that only lived on a server are replaced on the server and need no store release.
Railway says it notified providers. Do I still need to rotate?
Yes. A provider revoking a key on its side tells you nothing about the database password, the session secret or the registry token that sat in the same variable list. Create a new key at each issuer, update the app, and keep your own record that the old one no longer works.
I only changed the variable in the dashboard. Is that enough?
No. A variable in a platform is a copy of a secret the issuer still accepts. Zeabur's report says editing an environment variable does not change a database password, so the password has to be changed inside the database. For every key, the old value must be revoked where it was issued.
How do I know if someone used a key?
Read the usage and audit logs of the service that issued it, from 20 October 2026 for Railway and from 1 September 2026 for Zeabur dedicated servers, looking for requests from places and times you do not recognise. Quiet logs are unknown, not confirmed. Logs only show what the provider recorded.
Can a scan tell me whether my secrets leaked from a platform?
No. A scan of your live site reads what it shows an outsider, such as keys in shipped files or an exposed .env. It cannot see inside a hosting platform's storage. It can tell you whether your own site gives away the same secrets without any breach.
Should I move off Railway or Zeabur?
Zeabur announced on 17 October 2026 that its dedicated servers and shared clusters stop by 31 December 2026, so a migration is on a clock. For Railway, its preliminary report appeared on 22 to 23 October 2026 and a final forensic report was still to come at our check. Your code is yours either way if you hold a copy in your own repository.
Sources
All pages read on 24 October 2026.
- Security disclosure, Wednesday October 21st, Railway blog
- Preliminary report: October 21st security incident, Railway blog
- Incident QH8L8B3E: platform outage and token invalidation, Railway status
- Redeploy buckets and reconnect GitHub after the credential reset, Railway blog
- October 2026 security incident, preliminary report, Zeabur blog
- Zeabur is shutting down, Zeabur blog
- Secrets Management Cheat Sheet, OWASP Cheat Sheet Series
- Remediating a leaked secret in your repository, GitHub docs
- API keys, Stripe docs
- Understanding API keys, Supabase docs
- Environment variables in Expo, Expo docs
- Environment variables in EAS, Expo docs
