Railway env var breach: make secret rotation cheap

$ cat blog/railway-env-var-breach-secret-rotation.md
✓ incident
✓ secrets
✓ cloud
✓ incident response
5 min read
$ 

On October 22, 2026, the hosting platform Railway disclosed "anomalous activity" on systems that store customer environment variables, and said an unauthorized party "may have gained access to encrypted environment variables". In some cases, the contents were decrypted. The Hacker News covered the disclosure.

You can't prevent your platform provider's breach. You can decide how much one costs you, and that comes down to how quickly and safely you can rotate every secret you gave them.

What happened

According to Railway, the anomalous activity hit systems that store customer environment variables, and an unauthorized party may have accessed encrypted values, in some cases with decrypted contents. It affected "a subset of users"; Railway did not give a count.

How the intruder got in has not been disclosed. Nothing public says whether it was a stolen credential, a software flaw or something else, so this post doesn't speculate.

Other points from the report:

  • Researcher Taylor Monahan reported crypto wallets being drained whose private keys had been stored on Railway. Railway did not confirm this. The first known theft transaction was at 7:36 p.m., at least two hours before Railway's disclosure.
  • Railway rotated its bucket credentials, invalidated Railway API tokens, and notified upstream providers so they could revoke keys.
  • Railway's advice to customers: "Rotate environment variables, including any API keys, stored in Railway, as well as private registry credentials", and review logs.
  • Symantec's Dick O'Brien said there was no evidence linking the incident to a separate LLMjacking campaign, adding that "Railway hasn't said whether any have been abused."

Why it worked

The root cause isn't public, so this is about the general shape of the risk rather than Railway's systems.

Environment variables on a platform are a concentrated store of other people's secrets: database URLs, payment keys, cloud credentials, AI provider keys, registry tokens. Encryption at rest protects them from someone who copies a disk. It does less against someone who reaches the systems that need to decrypt those values to run your app. Once a value is out, it works until you revoke it, wherever it was stolen from.

That makes two properties decide the damage: how much each secret can do, and how long it takes you to replace it. A common pattern makes both worse. Here is an illustrative example, not any customer's code:

# Risky: a hardcoded fallback means the "real" key also lives in the repo,
# and the env var may never be set or rotated in some environments.
import os

PAYMENTS_KEY = os.environ.get("PAYMENTS_KEY", "<redacted-live-key>")
# Better: one source of truth, fail fast when it's missing,
# and a key scoped to the one job this service does.
import os

PAYMENTS_KEY = os.environ["PAYMENTS_KEY"]  # restricted key: create charges only

The second version has a single place to rotate, refuses to start with a stale copy, and uses a narrowly scoped key, so a leak is limited to what that key allows.

Make rotation boring

If rotating a key means hunting through repos, dashboards and teammates' laptops, it won't happen quickly during an incident. Things that help:

  • Keep an inventory. A list of every secret, where it's stored, who issued it and what it can do.
  • One source per secret. No copies in the repository, CI settings and the platform at the same time.
  • Scoped, short-lived credentials. Prefer per-service keys with minimal permissions, and short-lived tokens issued at deploy or run time where your providers support it.
  • Rehearse. Rotate a low-risk key on a schedule so the runbook is known to work.

Our secrets detection use case and the post on secrets in git history cover the repository side of this.

Some secrets can't be rotated

A wallet private key is not like an API key. If it leaks, there is no provider to revoke it, and the funds can be moved before you notice. Such keys don't belong in environment variables on a shared platform at all. Keep them in a dedicated signing service, a hardware or managed key store, or offline, and give the application only the ability to request a signature with limits.

attack, as reported where OpenRouting checks 1 Anomalous activity on env var systemsprovider infra, not code 2 Encrypted env vars may be accessedentry point not disclosed 3 Some contents decryptedoutside a code scan 4 Reported: wallet keys used to drainkeep keys out of env vars 5 Leaked keys work until rotated✓ Blast radius agent
The attack as reported, and where an OpenRouting check applies. Illustrative.

What to do now

If you use Railway, follow its advice first:

  1. Rotate every environment variable stored in Railway, including API keys, plus private registry credentials. Revoke the old values at the issuer, not just replace them in Railway.
  2. Review logs at each provider whose keys were stored there for use you don't recognise, starting from before the disclosure time.
  3. Move any wallet private keys or similar irrevocable secrets out of environment variables and into a signing service or key store.

For any platform, before the next incident:

  1. Build the inventory above and record which secrets each platform holds.
  2. Replace broad keys with scoped ones, and long-lived keys with short-lived tokens where possible.
  3. Remove hardcoded fallbacks and duplicate copies from repositories, and rotate anything that was ever committed.
  4. Script rotation for your most important keys and run it on a schedule.

How OpenRouting helps

OpenRouting can't see inside a platform's secret store, but it can shrink what a platform breach exposes by keeping secrets out of your code and narrowing what each one can do:

  • Semgrep secret rules flag cloud keys, tokens and passwords in the files of the repository you scan, so a hardcoded fallback or a committed .env shows up as a finding.
  • The secrets & data exposure agent reviews each secret finding, separates real credentials from test placeholders, and explains how to move the value out of the code.
  • The blast radius agent reviews findings for what a leaked credential could reach, such as an over-privileged key or a token with admin scope used where read access would do.
  • Secret values are replaced with [REDACTED] before any AI call, so triage by Claude, via Amazon Bedrock, never sees the secret itself.

What it won't catch

  • OpenRouting scans your repositories and, passively, your websites. It does not see a hosting provider's environment variables or infrastructure, and it can't tell you whether your values were among those accessed.
  • Secret rules read the files at the commit you scan, not your git history yet, so a key removed from the code but still in old commits needs rotating anyway.
  • It doesn't watch your providers' logs for abuse of a leaked key. That has to happen at each provider.
  • Findings come from a scan you run, manually or as a PR review.

Sources

Questions

What happened in the Railway environment variable breach?

Railway disclosed anomalous activity on systems that store customer environment variables and said an unauthorized party may have gained access to encrypted environment variables, in some cases with decrypted contents. It affected a subset of users; Railway did not give a count.

How did the intruder get into Railway?

That has not been disclosed. Nothing public says whether it was a stolen credential, a software flaw or something else.

What should Railway customers do now?

Rotate every environment variable stored in Railway, including API keys, plus private registry credentials, and revoke the old values at the issuer. Review logs at each provider whose keys were stored there, and move wallet private keys out of environment variables into a signing service or key store.

Can OpenRouting tell me whether my Railway secrets were exposed?

No. OpenRouting does not see a hosting provider's environment variables or infrastructure. It flags secrets in your repository's current files, so a platform breach exposes less.

Keep reading