Environment variables on Vercel, Railway, Render and similar platforms are safe enough for ordinary application secrets, but they are not a vault. The platform encrypts them and also holds the key, because it must produce plaintext at every build and boot. Mark secrets write only, and keep cloud admin keys, signing keys and long lived credentials somewhere else.
October 2026 showed why the distinction matters. Railway told customers to rotate every environment variable stored on the platform after a security incident, and Zeabur reported that an attacker read environment variable records from its platform database. Those customers had done nothing unusual. They had trusted a hosting provider with credentials, as almost every team on a platform as a service does.
This guide explains how platform environment variables work, what "encrypted at rest" does and does not protect, which secrets belong elsewhere, and what to do when your provider says "assume exposed". Platform features are described only from each platform's own documentation, read on 22 October 2026. It is an explainer, not a ranking of providers.
Key takeaways
- Encrypted at rest is not the same as safe. The platform must decrypt your variables to inject them, so anyone who reaches that decrypt path can read them.
- Write only matters more than encryption. Vercel Secret, Railway sealed and Netlify secret values cannot be read back through the dashboard or API, which closes the most common leak: a compromised teammate account or token.
- Build time variables can end up in public files.
NEXT_PUBLIC_andVITE_values are inlined into JavaScript sent to every browser. DockerARGandENVvalues persist in the image. - Some secrets never belong in platform variables: cloud admin keys, signing keys, CA keys, write scoped source control tokens and break glass credentials.
- OIDC removes whole classes of secret. Short lived federated tokens leave no long lived cloud key to steal.
- Rotate by blast radius: cloud and source control first, then data stores, then payment and AI keys. Create, deploy, verify, then revoke.
- Separate production values from preview. A preview deployment should never read production credentials.
How do platform as a service providers store environment variables?
Every platform in this category does the same basic job. You hand it key and value pairs through a dashboard, CLI or API. It stores them and injects them into your build and running service as ordinary process environment variables. Your code reads process.env.DATABASE_URL and has no idea where the value came from. What differs is how much each platform documents, and which controls it adds.
What the platforms' own docs say
Vercel says environment variable values "are encrypted at rest." Every variable is now either Config or Secret. Config values "remain readable after saving for members with access", while Secret values "are write-only after saving." You choose the environments a variable applies to (Production, Preview, Development or custom), and changes apply only to new deployments. Vercel redacts Secret values of 32 characters or longer from build logs and records an activity log event when it does.
Railway documents service, shared, reference and sealed variables. A sealed variable is "never visible in the UI nor can it be retrieved via the API", yet still reaches builds and deployments. Sealing is one way, and sealed values are not copied to PR environments, duplicated environments or external integrations. Variables are exposed during the build, in the running deployment, and through railway run and railway shell. The variables page does not describe encryption at rest.
Render offers per service variables, reusable environment groups and secret files, which appear at /etc/secrets/<filename> at runtime. Its docs say to keep secret values out of render.yaml and use placeholders filled in the dashboard. The page we read does not describe encryption at rest or who on a team can view values.
Heroku config vars trigger a restart and a new release whenever they change. With classic buildpacks they are "available at build time and runtime"; with Cloud Native Buildpacks they are runtime only by default. Heroku warns that values can be expanded into logged commands, so avoid writing sensitive variables to standard output.
Netlify adds scopes (builds, functions, runtime, post processing) and deploy contexts. A variable marked "Contains secret values" becomes write only outside the dev context, cannot use the post processing scope, and is checked by a build scan that fails the build if the value appears in any built file, including base64 and URI encoded forms.
What "who holds the key" means in practice
None of these docs say your secrets are encrypted with a key only you control. That is not a criticism; it is how the model has to work. A platform that injects plaintext at boot must produce plaintext without asking you, so the key, or a service allowed to use it, lives inside the platform.
The usual pattern is envelope encryption, which AWS describes as "encrypting plaintext data with a data key, and then encrypting the data key under another key." The top level key stays in a key management service or hardware security module. To decrypt, a component calls that service.
The design is good: a stolen database backup is useless on its own. But any internal service, administrator credential or compromised component allowed to call decrypt can read every value that key protects. Encryption at rest turns "who can read the database" into "who can call decrypt", and on a platform the answer always includes the platform's own deploy pipeline.
Why does "encrypted at rest" not mean safe?
Encryption at rest defends against one threat: someone getting the stored bytes without the ability to decrypt them, such as a lost disk or a leaked backup. It does nothing against the ways platform secrets actually leak:
- A compromised account or token reads them through the front door. If a value is readable to members with access, anyone who phishes a member or steals a project scoped API token can read it.
- The platform is breached at a layer that can decrypt. If an attacker reaches the service that injects variables, or an admin credential with decrypt rights, encryption is transparent to them.
- Your own code prints them in a debug log, an error page or a crash report.
- The build bakes them into an artifact such as a frontend bundle or an image layer.
- Preview environments receive production values and run code you have not reviewed.
- A dependency reads them. Any package that runs during your build or at runtime can read the whole environment.
What the October 2026 platform incidents showed
We cover these incidents in detail elsewhere, so here are only the points that bear on the general question.
Railway's status page shows builds paused across regions on 21 October, a security notice published that evening telling customers to rotate all variables stored on the platform, storage bucket credentials rotated, and all Railway API tokens invalidated at 04:17 UTC on 22 October. Cybersecurity News, citing Railway's disclosure, reported that some variables may have been accessed in decrypted form and that the disclosure did not explain how. Railway had not published an affected account count at the time of writing. Our write up: /resources/blog/railway-environment-variables-breach-october-2026.
Zeabur's preliminary report says an attacker read environment variable records from its platform database on 15 October, after an earlier intrusion, and that "long-lived admin credentials were stored in plaintext". Zeabur is shutting down. See /resources/blog/zeabur-shutdown-environment-variables-breach.
PingCAP disclosed on 19 October that an attacker used stolen service account credentials between 9 September and 7 October, and that exported data included a table of encrypted TiDB Cloud API key values. It is not an application host, but the shape is the same: encrypted values sitting near credentials that can reach them.
The lesson is not that any one provider was careless. A provider's internal credential is a single point that may unlock what it stores for every customer. You cannot audit that layer. You can decide what you put behind it.
Which secrets should never live in platform environment variables?
A useful test: if this value leaked today, could the attacker do something you cannot undo, or something that spreads beyond this one application? If yes, keep it out of a store the platform can decrypt at will.
| Secret type | Platform env var? | Better home | Why |
|---|---|---|---|
| Cloud root, admin or broad IAM keys | No | OIDC federation to a narrow role | One key reaches every resource in the account |
| Long lived cloud keys for the app | Avoid | OIDC, or a secrets manager fetch at boot | Short lived credentials expire on their own |
| Code signing or package publish keys | No | Hardware backed key service, CI trusted publishing | A stolen signing key lets an attacker ship as you |
| CA or important TLS private keys | No | Managed certificates or a key management service | Revocation is slow and public |
| Source control tokens with write scope | No | Short lived app installation tokens | Write access to source is write access to production |
| Break glass admin credentials | No | Offline vault with access logging | They exist for when everything else is compromised |
| Production database password | Yes, write only, production only | Secrets manager with rotation if supported | Damaging but contained to one store |
| Third party API keys (payments, email, AI) | Yes, write only | Restricted keys and spending caps | Rotatable, and scope limits damage |
| Session or JWT signing secret | Yes, write only | Same, with two key rotation | Rotation logs users out, so plan overlap |
| Feature flags, public IDs, analytics keys | Yes, readable config | Platform env var | Not secret |
Platform variables are fine for secrets whose blast radius is one application and whose rotation is cheap. They are the wrong place for secrets whose blast radius is the whole company.
How do build time and runtime variables differ, and which ones get baked into bundles?
This is the most common way platform secrets leak, and it has nothing to do with the platform's security.
Runtime variables
A runtime variable is read by your server process at startup or per request and stays in server memory unless you print it or send it out. Next.js says variables without the public prefix "are only available in the Node.js environment."
Build time variables
A build time variable is read while your code is compiled or packaged, and whatever the build does with it becomes part of the output. Next.js will "inline" any NEXT_PUBLIC_ value "at build time, into the js bundle that is delivered to the client", frozen at the value present when next build ran. Vite does the same with VITE_ and says those variables should "not contain sensitive information such as API keys." Docker's docs warn that build arguments and environment variables "persist in the final image", where anyone who can pull the image can read them.
The practical rule
| Where the value is read | Where it can end up | Safe for secrets? |
|---|---|---|
| Server code at request time | Server memory, logs if printed | Yes, with care in logging |
| Server code during static generation | Prerendered HTML and JSON | Only if never rendered into output |
NEXT_PUBLIC_ or VITE_ variable | Every visitor's browser | Never |
Docker ARG or ENV | Image layers and every registry copy | Never |
Docker RUN --mount=type=secret | One build step | Yes |
| Build logs | Log storage, everyone with log access | Redaction helps; do not rely on it |
Vercel's log redaction applies only to Secret values of 32 characters or more, and Netlify's scan fails the build when a secret value appears in built files. Both are safety nets, not a reason to put secrets in client prefixed variables.
What do a secrets manager, OIDC workload identity and short lived tokens change?
Three tools solve different parts of the problem.
A secrets manager
A dedicated secrets manager stores values encrypted under keys in your own cloud account, logs every read and can rotate some credentials automatically. Your app fetches values at startup or on demand.
What it changes: the plaintext no longer sits in the hosting platform's store, you get your own audit log, and you can rotate centrally instead of editing five dashboards. What it does not change: your app still needs a credential to reach the secrets manager. If that credential is a long lived key in a platform variable, you have moved the problem one hop. OIDC fixes that hop.
The OWASP Secrets Management Cheat Sheet describes environment variables as "generally accessible to all processes" and notes that they can end up in logs or dumps. It also points out that restarting an application does not revoke stolen credentials; they stay usable until the backing service expires or revokes them.
OIDC workload identity federation
With OpenID Connect federation, the platform vouches for your workload with a signed, short lived token. Your cloud provider trusts that issuer and swaps the token for temporary credentials scoped to one role.
Vercel describes this as issuing "short-lived, non-persistent tokens" so you "can avoid storing long-lived credentials as Vercel environment variables." Builds receive VERCEL_OIDC_TOKEN; functions receive the token in the x-vercel-oidc-token header. Vercel reuses a function token for up to 90 minutes, function tokens live for two hours, and Vercel recommends the Team issuer mode, which gives your team its own issuer URL.
GitHub Actions works the same way for CI. Each job gets a JWT whose claims name the repository, branch and environment, the cloud provider checks them against the role's conditions, and the resulting credentials are valid only for the job. GitHub's example subject is repo:octo-org/octo-repo:environment:prod.
What it changes: no long lived cloud key exists in your platform variables, and rotation is automatic. What it does not change: if an attacker can make the platform issue a fresh token for your project, they can exchange it. Federation narrows window and scope; it does not remove trust in the issuer. That is why the trust conditions matter as much as the federation itself.
Short lived and scoped tokens everywhere else
Many APIs offer restricted keys or keys with expiry. A payment key that can only create charges, or an AI key with a monthly spending cap, is worth far less to an attacker than an unrestricted one.
| Approach | Where plaintext lives | Lifetime | Who can decrypt | Best for |
|---|---|---|---|---|
| Platform env var, readable | Platform store | Until rotated | Platform and members with access | Non secret config |
| Platform env var, write only | Platform store | Until rotated | Platform deploy pipeline | App scoped API keys, DB passwords |
| Secrets manager at boot | Your cloud account | Until rotated, often automated | Your role, your audit log | Shared or regulated credentials |
| OIDC federation | Nowhere persistent | Minutes to hours | Issued per workload | Cloud access from builds and functions |
| Docker build secret mount | One build step | One step | Builder only | Private registry tokens at build |
What is the rotation order when your platform says "assume exposed"?
Rotate in order of how fast an attacker can use each credential and how far the damage spreads. Our guide /resources/blog/breach-in-the-news-do-i-need-to-rotate-credentials covers whether to rotate at all; once a provider says rotate everything, only the order is left.
Step 0: list names before you touch anything
Export every variable name, not value, from every project, service and environment. For each, note what it unlocks, its scope, and whether rotating it will break a running service.
# Vercel: names per environment (Secret values are never returned)
vercel env ls production
vercel env ls preview
# Heroku: names only
heroku config --app my-app --shell | cut -d= -f1
On Railway, use each service's Variables tab or railway variables in a linked directory. Sealed values are not printed; you only need the names.
Step 1: cloud, identity and source control credentials
Rotate first anything that can create more access: cloud access keys, service account keys, write scoped source control tokens, CI and deploy tokens, registry push credentials. An attacker with these can plant persistence that survives every later rotation. After revoking, check the provider's audit log for use you did not make, such as CloudTrail calls from the old access key ID or the token's last used time on your source control host.
Step 2: data stores
Database, cache and object storage credentials. Railway's own guidance listed PostgreSQL, MySQL, MongoDB and Redis credentials explicitly.
-- PostgreSQL: set a new password for the application role
ALTER ROLE app_user WITH PASSWORD 'new-generated-value';
If your database allows two active credentials, use that to avoid downtime.
Step 3: money and metered APIs
Payment, AI provider, SMS and email keys are monetised fast. Railway's status page told customers to review usage at AI, payment and cloud providers.
Step 4: application secrets
Session, JWT, webhook signing and app encryption keys. Rotating a session secret logs everyone out, so accept old and new keys for a short overlap and sign only with the new one.
Step 5: everything else
Analytics write keys and narrowly scoped internal tokens.
Create, deploy, verify, revoke, and when to break the rule
Vercel's rotation guide gives the normal order: update the platform "before you invalidate the old credential", redeploy, verify, then invalidate. For team level variables, redeploy every linked project first. Old deployments keep old values, so they fail once the old credential is revoked.
Break the rule for step 1 credentials when you have evidence of misuse. If audit logs show calls you did not make, revoke now and accept the outage.
Railway customers met one more trap in October 2026: with builds paused, you cannot deploy a new value, so revoking the old one breaks production with no recovery path on that platform. For your highest value credentials, either keep them out of the platform or document how to run the service elsewhere.
How do you limit blast radius per environment and per service?
Most platforms give you the controls. Few teams use all of them.
Separate production values. Vercel's optional Separate Production Secret Values policy forces each Secret to use a different production value than Preview, Development and custom environments. Railway does not copy sealed variables into PR environments. Netlify lets you set values per deploy context, and its sensitive variable policy controls whether untrusted deploys, such as those from forks of public repositories, see sensitive variables.
One credential per service. If three services share one database user, a leak from any of them forces a rotation that touches all three. Give each service its own user and its own cloud role. Shared variables, team level variables and environment groups are convenient fan out points; use them for config and keep secrets at the narrowest scope that works.
Scope platform access. Anyone who can read Config values, trigger deploys or edit variables is part of your secret surface. Review team membership, remove unused personal tokens, prefer project scoped tokens and enforce single sign on and multi factor authentication where your plan allows.
Keep secrets out of the build. If a value is only needed at runtime, do not expose it to the build, where every dependency's install script can read it. Netlify scopes and Heroku's runtime only default for Cloud Native Buildpacks both help.
What questions should you ask a PaaS vendor before trusting it with production secrets?
You cannot audit a provider's internals, but these answers tell you a lot. Ask in writing, keep the answers, and repeat after any incident.
- How are environment variables encrypted at rest, and where is the top level key held?
- Which internal systems and roles can decrypt customer variables, and how is that access logged and reviewed?
- Do you offer write only variables, and can we enforce them by policy?
- Can we keep production values out of preview and fork deployments?
- Do you support OIDC federation to our cloud, with per project and per environment claims?
- Do you redact secrets from build and runtime logs, and under what conditions?
- What audit events do we get for reading and changing variables and for creating API tokens?
- Will you tell us which of our variables were accessed in an incident, and how fast?
- If you pause builds during an incident, how do we deploy rotated credentials?
- Which independent assessments cover the systems that store variables?
A step by step hardening walkthrough
A practical sequence for a typical web app on a platform as a service with a cloud database and a few third party APIs.
1. Inventory and classify
List names per project and environment, as in Step 0 above. Tag each: public config, app scoped secret or high value secret. High value secrets are migration candidates.
2. Find secrets reaching the browser
# Client exposed variables your code references
grep -rnoE "(NEXT_PUBLIC|VITE)_[A-Z0-9_]+" src app pages | sort -u
# Build, then search client output for secret formats you use
npm run build
grep -rlE "sk_live_|BEGIN [A-Z ]*PRIVATE KEY" .next/static dist 2>/dev/null || echo "nothing found"
Adjust the patterns to your providers' key formats. Anything found is already public: rotate it and move the calling code to a server route.
3. Make every remaining secret write only
vercel env add STRIPE_SECRET_KEY production --type secret
Vercel's CLI accepts --type config or --type secret, and a saved Secret cannot be converted back to Config in place. On Railway, seal the variable from its three dot menu. On Netlify, tick "Contains secret values" or pass --secret on the CLI.
4. Separate production values
On Vercel, an owner enables Require Separate Values under the team's Security settings. Elsewhere, set per environment values and confirm previews do not inherit production secrets.
5. Replace long lived cloud keys with OIDC
For a Vercel function that reads from AWS, follow Vercel's AWS guide for your team's issuer URL and subject format, and limit the role's trust policy to your project and production environment. For GitHub Actions deploying to AWS:
name: deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: prod
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-prod
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-prod-bucket
The role's trust policy pins it to one repository and environment:
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:my-org/my-app:environment:prod"
}
}
}
Once this works, delete AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from every platform and CI store and deactivate the old keys.
6. Move shared or regulated credentials to a secrets manager
aws secretsmanager get-secret-value \
--secret-id prod/app/database \
--query SecretString --output text
In code, fetch with your cloud SDK at boot using the workload's own identity, keep the value in memory, and turn on managed rotation where your database engine supports it.
7. Use build secret mounts in Dockerfiles
# syntax=docker/dockerfile:1
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
COPY . .
RUN npm run build
docker build --secret id=npmrc,src=$HOME/.npmrc -t my-app .
docker history --no-trunc my-app | grep -iE "token|secret|password" || echo "nothing obvious"
Docker documents that a secret mount exposes the value only for the instruction that uses it.
8. Stop printing the environment
grep -rnE "console\.(log|error)\(process\.env\)|JSON\.stringify\(process\.env|print\(os\.environ" .
Also check whether your error reporting tool attaches environment variables to events, and turn that off.
9. Write the runbook now
One page: the variable inventory, the rotation order above, who owns each external account, and how to deploy if your platform's builds are paused. Test it on staging once.
Common mistakes
- Treating "encrypted at rest" as the end of the conversation. It protects stored bytes, not against anyone who can call decrypt, including a teammate's compromised account.
- Leaving secrets as readable config. Make every secret write only so a phished teammate cannot simply read the list.
- Putting keys in
NEXT_PUBLIC_orVITE_variables "for now". They ship to every visitor. Only rotation fixes it. - Using
ARGorENVfor tokens in a Dockerfile. Use a secret mount. - Sharing one value across production and preview.
- Storing cloud admin keys "in case the app needs them". Give the app a narrow OIDC role instead.
- Revoking before redeploying, unless you have evidence of active misuse.
- Forgetting old deployments and other projects that use a team level variable.
- Rotating without checking for use. Only the downstream provider's audit log tells you whether the old key was already used.
- Expecting a precise list from your provider. Railway's October guidance was to rotate everything while it investigated. Plan for that.
FAQ
Are Vercel environment variables secure?
Vercel's docs say all values are encrypted at rest. Secret type variables are write only after saving, and long Secret values are redacted from build logs. That is reasonable for app scoped API keys and database passwords. For cloud access, Vercel documents OIDC federation so you do not store long lived cloud credentials as variables at all.
Are environment variables safe for secrets in general?
They are a common, acceptable way to deliver secrets to a process; the Twelve-Factor App recommends keeping config in the environment rather than in code. OWASP notes the weaknesses: the whole process can read them and they can leak into logs or dumps. Use them for delivery, keep the source of truth somewhere with access logging, and never print them.
Are .env files secure?
A .env file is plaintext on disk. It is fine for local development if it is git ignored and holds development credentials only; Next.js's default template ignores .env files for this reason. Never copy production values into one.
What is the difference between a Vercel Secret and a Config variable?
Config values stay readable to members with access. Secret values are write only, so you can replace them but not view them. Both are encrypted at rest, and a saved Secret cannot be converted to Config in place.
What are Railway sealed variables?
A sealed variable is hidden from the dashboard and API but still injected into builds and deployments. Sealing cannot be undone, and sealed values are not copied to PR environments, duplicated environments or external integrations.
Do I need a secrets manager if my platform encrypts variables?
Not for every secret. It helps most for credentials shared by several services, regulated environments, automatic rotation, and anything whose reads you need to audit yourself. For cloud access, OIDC often removes the stored secret entirely.
Can a malicious npm package read my environment variables?
Yes. Any code running in your build or server process can read its environment, including install scripts and runtime dependencies. That is one more reason to keep high value credentials out of build environments.
Should I put AWS access keys in Vercel or Netlify environment variables?
Avoid it where you can. Vercel documents OIDC federation with AWS, Google Cloud and Azure, and GitHub Actions supports the same pattern. If you must store a key, scope it tightly, mark it write only and set a rotation date.
How often should I rotate secrets on a hosting platform?
Immediately when someone with access leaves, when a provider reports an incident, or when a value shows up anywhere it should not. Otherwise, match the schedule to the secret's value and the cost of rotating. Federated credentials rotate themselves.
Fix it without waiting for upstream
Platform secrets and vulnerable dependencies meet in one place: every package in your build and runtime can read the environment those secrets live in. Shipping fewer known vulnerable components means fewer ways for an attacker to get code running next to your credentials.
In incidents like this one, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
Where Safeguard fits, and where it does not
Limits first. Safeguard does not store your secrets, does not run your hosting platform and cannot see inside a provider's key management. If your provider's variable store is breached, rotation is your job and your provider's.
Where it helps:
- Vendor records. The Vendors area of Safeguard's compliance suite gives you one place to record each hosting provider, attach the documents and questionnaire answers you collected with the questions above, and track review dates.
- Knowing what runs next to your secrets. Safeguard scans repositories, container images and SBOM files for dependencies, matches them against vulnerability databases and uses reachability analysis to rank what your code calls. Policies and gates can block a merge or release that brings in a known vulnerable version.
- Migration work with a human in the loop. The Safeguard CLI's assistant can edit code and run commands with your approval, so moving a function to OIDC or replacing a Dockerfile
ARGwith a secret mount is a change you can ask for, review step by step and push yourself.
Download the CLI from safeguard.sh/download and read the CLI docs.
See how Safeguard would help
These are real product sessions. None touches your hosting platform's variables; they show the approval driven workflow you would use to change code and configuration.
In this CLI session you ask the assistant to fix a lodash CVE. It reads the finding and advisory, asks before each command, edits package.json, runs npm install and npm test with your approval, prints a summary and pushes nothing. The same loop fits a secrets hardening change, such as replacing a Docker ARG token with a build secret mount.
Click through it at your own pace, or open it full screen.
This demo sets up the runner on your own machine, approves it with its device code, then scans from the terminal. The scan runs on a machine you control, which suits teams tightening where their build context travels.
Click through it at your own pace, or open it full screen.
This real Android session sends work to a computer running the CLI and approves each command on the phone with Allow once, Allow for turn or Deny. During a provider incident, whoever is working through the rotation runbook away from a desk still approves every step.
Click through it at your own pace, or open it full screen.
Quick check
Your Next.js app reads a payment key from NEXT_PUBLIC_PAYMENT_KEY, stored as a write only Secret on your platform. Is the key protected?
No. Next.js inlines every NEXT_PUBLIC_ value into the JavaScript bundle at build time, so it ships to every visitor however the platform stores it. Rotate the key and move the calling code to a server route.
Your provider says rotate every environment variable, and builds are paused. What do you rotate first, and what do you watch for?
Start with cloud, identity and source control credentials, because they can create new access. Watch the deploy trap: revoking an old credential before you can deploy the new one breaks production. Revoke at once only where audit logs show misuse; otherwise create, deploy, verify, then revoke as soon as builds return.
Sources
- Vercel docs: Environment variables
- Vercel docs: Config and Secret environment variables
- Vercel docs: Rotating environment variables
- Vercel docs: OpenID Connect (OIDC) Federation
- Railway docs: Using variables
- Railway status: incident QH8L8B3E
- Render docs: Environment variables and secrets
- Heroku Dev Center: Configuration and config vars
- Netlify docs: Environment variables overview
- Netlify docs: Secrets Controller
- Next.js docs: Environment variables
- Vite docs: Env variables and modes
- Docker docs: Build secrets
- GitHub docs: OpenID Connect
- AWS KMS developer guide: Cryptography essentials
- OWASP Secrets Management Cheat Sheet
- The Twelve-Factor App: Config
- PingCAP: Security update, October 2026
- Cybersecurity News: Railway security incident
- Safeguard: Zeabur shutdown and environment variables breach
Related reading: /resources/blog/environment-variables-for-secrets-where-they-leak and /resources/blog/oidc-vs-static-credentials-in-ci.
Last reviewed: 22 October 2026. Platform features change often; check each provider's linked documentation for current behavior.