# After Railway's October 2026 security incident: what to rotate and check

By José (https://mobius1.io/about/). Published 2026-10-26.
Canonical: https://mobius1.io/guides/railway-security-incident-what-to-rotate/

If you stored secrets in Railway environment variables before October 21, 2026, Railway's advice is to rotate them. Start with AI provider keys, because Railway says that is what the attacker was after. Then rotate Stripe keys and webhook secrets, database passwords, OAuth client secrets and cloud keys. For each one, revoke the old value, deploy the new one, and read that vendor's usage or request logs for the exposure window.

Railway also recommends removing public network access to your databases. This page goes through the order, where each setting lives, and what to look for in the logs. It is based on what Railway had published by October 26, 2026. Its forensic investigation was still open then.

## What happened, according to Railway

Railway's [security disclosure of October 21](https://blog.railway.com/p/security-disclosure-wednesday-october-21st) said "an unauthorized third party may have accessed encrypted environment variables and, for some of them, obtained the decrypted contents." Its [preliminary report](https://blog.railway.com/p/preliminary-report-october-security-incident) of October 22 adds more detail:

- Railway believes the attack ran from October 20, 13:58 UTC to October 22, 03:32 UTC. The second time is when Railway confirmed the attacker no longer had access to internal systems.
- On the motive: "Early investigations tell us this attack was attempting to obtain AI provider API keys to perform distillation attacks."
- On scale: "at most 1.85% of all workspaces had some environment variables potentially compromised. This represents, numerically, about 100,000 workspaces."
- Railway says it could not tell which variables were decrypted. In its words, "this query alone cannot identify specifically which keys in the affected customers project/service were affected."
- "The attacker did not access Railway user accounts as part of this incident." Railway still revoked all Railway access tokens as a precaution.
- Existing deployments stayed online. New builds and deploys were paused and later restored.

Still unconfirmed when the report was written: whether the attacker reached customer source code ("we are not ruling out that they accessed user source code"), how the exploits worked, and the final scope. Railway says it will publish a follow-up when the forensic investigation ends.

### Who is being told, and how

Railway says it is contacting customers with definite impact. It is also contacting customers it considers high risk, a group larger than the 1.85%. It names two kinds of high risk: workspaces with a very large number of environment variables, and environments with many AI vendor keys. Railway also sent keys to vendors including GitHub, GitLab, Anthropic, OpenAI, OpenRouter, Stripe and others so they could revoke them. For some vendors it sent every key stored on the platform. Railway says a revocation email from a vendor "does not imply that their credentials were impacted by the incident."

So if you got no email, that does not mean you are in the clear, and if you did get one, that does not mean your key was used. Railway's recommendation applies to every customer who signed up before October 21: rotate sensitive variables stored on Railway.

## Which keys should I rotate first?

Rotate in order of what an attacker can spend or take fastest. For every item, the Railway side is the same: open the service, click **Variables**, set the new value, and deploy the staged change. Containers only read variables at startup, so a service you don't redeploy keeps the old value. If you use a [shared variable](https://docs.railway.com/variables), edit it once in Project Settings.

| Priority | Secret | Where to rotate | Where to look for abuse |
| --- | --- | --- | --- |
| 1 | AI provider keys (OpenAI, Anthropic, OpenRouter) | Each provider's API keys page | Usage grouped by API key; request logs |
| 2 | Stripe secret, restricted and webhook keys | API keys page (live mode); Workbench Webhooks tab | The old key's request logs; payments, payouts, webhooks |
| 3 | Database URLs and passwords | Railway Database tab → Config → Regenerate | Railway audit logs; failed logins; `pg_stat_activity` |
| 4 | OAuth client secrets | The identity provider's client settings | The provider's audit or sign-in logs |
| 5 | Cloud keys (AWS, Google Cloud) | IAM access keys; service account keys | CloudTrail; Cloud Audit Logs; billing |

### 1. AI provider keys

**OpenAI.** Open the API keys page for the project that owns the key and delete it. Organization-level and legacy user keys are listed separately. Create a replacement and copy it, because it is shown only once. To check for abuse, open Usage, select the project and group by API key. Compare token volume, request counts and the models used against your normal traffic. OpenAI's [key safety guide](https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety) says to rotate a leaked key from the API Keys page and contact them through help.openai.com. It also recommends monthly spend limits with hard enforcement. Railway's [OpenAI walkthrough](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-openai-usage) covers the menus step by step.

**Anthropic.** In the Claude Console, open the API keys page (`platform.claude.com/settings/keys`). Click the three-dot menu next to the key and choose **Delete API key**, per [Anthropic's key guidance](https://support.claude.com/en/articles/9767949-api-key-best-practices-keep-your-keys-safe-and-secure). Then review the Usage page (`platform.claude.com/usage`) and the Logs page (`platform.claude.com/logs`). Railway's [Anthropic walkthrough](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-anthropic-usage) suggests grouping usage by API key. If a key you only use with one model suddenly shows another model, treat that as a strong signal. If an Admin key (`sk-ant-admin01-...`) was stored on Railway, delete it too.

**OpenRouter and others.** A leaked OpenRouter key spends your prepaid credits directly. Railway's [OpenRouter walkthrough](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-openrouter-usage) recommends disabling the key rather than deleting it, so you keep its usage history. Then review the Activity page grouped by key and model. Railway has also published guides for other providers on its [engineering blog](https://blog.railway.com/engineering).

### 2. Stripe secret keys and webhook secrets

On the Stripe **API keys** page, click the overflow menu next to the key, choose **Rotate key**, and pick an expiration. If you choose **Now**, the old key is deleted immediately. Otherwise both keys keep working for up to 7 days ([Stripe: API keys](https://docs.stripe.com/keys)). If you think the key may be compromised, choose Now. Rotate restricted keys (`rk_live_`) too. Publishable keys (`pk_`) are meant to be public.

Webhook signing secrets are separate from API keys. In Workbench, open the **Webhooks** tab, click each endpoint, open the overflow menu and click **Roll secret**. You can expire the old secret immediately or keep it for up to 24 hours ([Stripe: webhooks](https://docs.stripe.com/webhooks)).

To check for abuse, open the old key's overflow menu and click **View request logs**. Stripe keeps those logs for rotated and deleted keys too. Look for IP addresses, endpoints and volumes your integration doesn't produce. Then review Payments, Payouts and external bank accounts, webhook endpoints you didn't create, and team members. Railway's [Stripe walkthrough](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-usage-in-stripe) lists these checks.

### 3. Database URLs and passwords

For a database created from Railway's PostgreSQL template, open the database service, click the **Database** tab, then **Config**, and click **Regenerate** next to the password. Railway changes the password inside PostgreSQL and updates `POSTGRES_PASSWORD`, `PGPASSWORD`, `DATABASE_URL` and `DATABASE_PUBLIC_URL`. Don't change the password by hand with `ALTER USER`, because that leaves the variables and the database out of sync ([Railway: rotate PostgreSQL credentials](https://blog.railway.com/p/security-disclosure-recommendation-rotate-postgresql-database-credentials)). Railway has matching guides for MySQL, Redis and MongoDB.

Regenerating restarts the database and drops every session. Next, redeploy every service that uses it. Services that use `${{ Postgres.DATABASE_URL }}` pick up the new value when they redeploy. Services with a pasted connection string don't, and neither do outside tools such as CI, BI tools or local scripts.

To check for misuse, Railway points to its audit logs (who viewed or changed variables) and to the database's deploy logs for `authentication failed`. Run `SELECT rolname FROM pg_roles;` to look for roles you didn't create. After the restart, list sessions with `pg_stat_activity`. Any session you don't recognize connected with the new password, so find out how it got it.

### 4. OAuth client secrets

If your app signs users in with Google, the secret is in the Google Auth Platform **Clients** page. Open the client, click **Add Secret**, deploy the new secret, then click **Disable** on the old one and delete it once nothing breaks ([Google: Manage OAuth Clients](https://support.google.com/cloud/answer/15549257)). For other identity providers, look for the client or app settings and generate a new secret there. If you also stored GitHub tokens on Railway, work through Railway's [GitHub checklist](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-github-access): security log, authorized apps, SSH keys, personal access tokens, and each repository's deploy keys and webhooks.

### 5. Cloud keys

**AWS:** in IAM, find the user that owns the key, create a new access key on the **Security credentials** tab, then deactivate the old one. In CloudTrail **Event history**, filter by the key ID and check every Region. Look for `RunInstances`, `CreateUser`, `CreateAccessKey` and policy changes ([Railway: AWS](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-aws-access)). **Google Cloud:** create a new service account key, disable the old one with `gcloud iam service-accounts keys disable`, and search Logs Explorer for the service account's activity ([Railway: GCP](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-gcp-access)). Compare billing for the exposure window against the month before. Compute, GPU and Vertex AI are the usual targets.

Railway also recommends checking audit logs in container registries such as Docker Hub, and its own Railway tokens were revoked. To get CI deploys working again, create a new `RAILWAY_TOKEN` or `RAILWAY_API_TOKEN` ([Railway: recover failing deploys](https://blog.railway.com/p/security-disclosure-recommendation-recover-failing-deploys)).

## How do I remove public access to my Railway database?

Railway databases are private by default. Public access is something you add: in the database service's **Settings → Networking**, adding **Public Access** creates a TCP proxy and fills in `DATABASE_PUBLIC_URL` ([Railway: PostgreSQL](https://docs.railway.com/databases/postgresql)). Open that same section. If a TCP proxy is listed (a host like `shuttle.proxy.rlwy.net` with a port, per [Railway: TCP proxy](https://docs.railway.com/networking/tcp-proxy)), remove it unless something outside the project truly needs it. Railway's rotation guide puts it this way: with public access on, the credential "is usable from anywhere on the internet through the TCP proxy until you rotate."

Your app services can still reach the database over Railway's private network. Anything that relied on `DATABASE_PUBLIC_URL`, such as a laptop or a BI tool, will stop working, so turn it back on only for as long as you need it.

## Are any of my secrets in the frontend bundle?

Rotating does nothing for a key that ships to every browser. Two prefixes are the usual cause:

- **Next.js:** a variable prefixed with `NEXT_PUBLIC_` is inlined into the JavaScript sent to the browser at build time ([Next.js docs](https://nextjs.org/docs/app/guides/environment-variables)).
- **Vite:** variables prefixed with `VITE_` are exposed in client-side code, and Vite's docs say they "should not contain sensitive information such as API keys" ([Vite docs](https://vite.dev/guide/env-and-mode)).

List your variables and check every one with either prefix. A Stripe publishable key or an analytics ID is fine there. An OpenAI, Anthropic or Stripe secret key is not. OpenAI says the same: never deploy your key in browsers or mobile apps, and route requests through your own backend. If you find one, move the call to a server route, rename the variable without the prefix, rotate the key and rebuild. The old value stays in any bundle that was already served.

## What should I tell my own customers?

It depends on what the logs show. Railway has not said that customer data in databases was read. It said environment variables were decrypted for a subset of workspaces and that source code access was not yet ruled out.

- If the logs are clean and you rotated everything, you may not need to announce anything. Prepare a short, factual answer for anyone who asks: you run on Railway, you rotated all credentials stored there on a given date, and you reviewed provider logs and found no misuse.
- If you found misuse that touches customer data or payments, such as unknown database sessions, Stripe activity you didn't make or new webhook endpoints, keep the evidence and talk to a lawyer about notification duties before you send anything. The rules depend on where you and your customers are.
- If a customer's security review asks about it, give dates. Say when you rotated each class of secret, which logs you checked, and what changed, such as removing the database TCP proxy.

Stick to Railway's published facts and your own findings, and don't guess at scope.

## Where Mobius fits

Mobius would not have detected or prevented a breach inside Railway's platform, and nothing here suggests your domain was affected. The [free check](https://mobius1.io/?p=railway-security-incident-what-to-rotate#check) looks up your domain in public sources only: certificate transparency logs, DNS and public scan data. It never connects to your systems. It can show what is visible from outside, such as a forgotten subdomain. Any live check against your systems needs proof that you own the domain and a scope you approve first.

## Sources

- [Railway: Preliminary Report, Oct 21st Security Incident](https://blog.railway.com/p/preliminary-report-october-security-incident) (October 22, 2026)
- [Railway: Security Disclosure, Wednesday October 21st](https://blog.railway.com/p/security-disclosure-wednesday-october-21st)
- [Railway: Check for Unexpected OpenAI Usage](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-openai-usage)
- [Railway: Check for Unexpected Anthropic Usage](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-anthropic-usage)
- [Railway: Check for Unexpected OpenRouter Usage](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-openrouter-usage)
- [Railway: Check for Unexpected Usage in Stripe](https://blog.railway.com/p/security-disclosure-recommendation-check-for-unexpected-usage-in-stripe)
- [Railway: Rotate PostgreSQL Database Credentials](https://blog.railway.com/p/security-disclosure-recommendation-rotate-postgresql-database-credentials)
- [Railway: Check for Anomalous AWS Access](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-aws-access)
- [Railway: Check for Anomalous GCP Access](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-gcp-access)
- [Railway: Check for Anomalous GitHub Access](https://blog.railway.com/p/security-disclosure-recommendation-check-for-anomalous-github-access)
- [Railway: Recover Failing Deploys](https://blog.railway.com/p/security-disclosure-recommendation-recover-failing-deploys)
- [Railway docs: PostgreSQL](https://docs.railway.com/databases/postgresql) and [TCP Proxy](https://docs.railway.com/networking/tcp-proxy)
- [OpenAI: Best practices for API key safety](https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety)
- [Anthropic: API key best practices](https://support.claude.com/en/articles/9767949-api-key-best-practices-keep-your-keys-safe-and-secure)
- [Stripe: API keys](https://docs.stripe.com/keys) and [Webhooks](https://docs.stripe.com/webhooks)
- [Google Cloud: Manage OAuth Clients](https://support.google.com/cloud/answer/15549257)
- [Next.js: Environment variables](https://nextjs.org/docs/app/guides/environment-variables)
- [Vite: Env variables and modes](https://vite.dev/guide/env-and-mode)
