Environment variables and secrets: where they should never be

The places we find API keys and passwords during audits, why each is dangerous, and the one place secrets belong.

4 minread 860words last updated

The short answer

A secret is any value that grants access: an API key for the email service, a database password, a token for the automation platform, a signing key for webhooks. Wherever a secret is stored, whoever can read that place holds that access, which is why where secrets live matters more than how long or random they are. During audits of inherited sites we find secrets in repositories, current and historical, in front-end code every visitor downloads, in build and deployment logs, in chat messages, in shared documents and spreadsheets, in screenshots and in the environment files developers keep on laptops. Each is a leak waiting to be found, and several are found routinely by automated scanners. Secrets belong in one place: the platform’s secret storage, injected into the running function or the build, scoped per environment, with access limited to named people and never printed. A secret found anywhere else is revoked and replaced immediately, and the place it leaked from is fixed.

Where we find secrets and why each is dangerous

WhereWhy it is thereWhy it is dangerous
Committed in the repositoryConvenience during developmentEvery clone, fork, backup and past collaborator has it; history keeps it after removal
In front-end JavaScriptThe developer called the API from the browserEvery visitor downloads it; it is public
In build or deployment logsA script printed configurationLogs are kept, shared and rarely protected
In chat messages and emailShared quickly between colleaguesSearchable forever, in accounts that get compromised
In shared documents and spreadsheetsThe team’s password listWide access, no audit, copied everywhere
In screenshotsDocumentation or a support ticketStored in image libraries and tickets indefinitely
In environment files on laptopsLocal developmentLost or stolen devices; synced to cloud folders
In a content system’s settings pagesA plugin wanted a keyReadable by every admin; often exposed by plugin flaws
In error messages on the siteVerbose errors in productionShown to whoever triggers the error

The rules

  1. Every secret lives in the platform’s secret storage, per environment, never anywhere else.
  2. Front-end code holds only values designed to be public; everything else is called through a function.
  3. Repositories contain an example environment file with names and no values; real environment files are ignored by version control.
  4. Nothing prints secrets: logs, error messages and build output are checked.
  5. One key per integration, with the narrowest permissions the provider allows, so a leak is contained.
  6. Access to secret storage is limited to named people; leavers are removed the same day.
  7. Scanning is on: the repository is checked for secret patterns on every change.
  8. A leak means revoke and replace now, then fix the source, then check the provider’s usage logs.

Public keys and real keys

Some values are designed for the browser: a payment provider’s publishable key, an analytics measurement identifier, a map key restricted to your domain. They can be in front-end code because they cannot do harm on their own or are restricted to your site. The test is what the value can do if a stranger has it. If it can send, charge, read, write or delete, it is a real secret and belongs in secret storage behind a function.

What this means for you

Secrets grant access to whoever can read where they are kept. Keep every one in the platform’s secret storage, per environment, with named access; keep front-end code free of anything that can act; keep repositories, logs, chats, documents and screenshots free of them; scope each key narrowly; scan continuously; and treat any secret found elsewhere as leaked and replace it. The discipline costs nothing and removes the most common way a small business hands its accounts to strangers.

Written by the CivSec S.M.A.R.T team

We build and run websites, software and AI systems for businesses. We write about what we see in that work, in plain language, and we update articles when things change.

Last checked . Spotted something outdated? Tell us.

Frequently asked questions

The key is in a private repository. Is that not safe?

No. Private repositories are cloned to every developer's laptop, backed up, forked, occasionally made public by mistake and accessible to everyone who ever had access. A key committed once stays in the history even after it is removed from the current version. Repositories hold code; secrets hold access; they must not share a home.

What about a key in the website's JavaScript?

Anything in front-end code is public: every visitor's browser downloads it and anyone can read it in a few clicks. A key there is a key published on the internet. Some keys are designed to be public, such as a payment provider's publishable key or an analytics identifier, and those are fine. Anything that can charge, send, read or write is not, and belongs behind a function that holds the real key.

How do we know if a secret has already leaked?

Search the repository history for key patterns, check build logs, review chat and document search for the strings, and use the provider's dashboard to see where a key has been used from. Most providers now scan public repositories and revoke keys they find, which is a sign yours was exposed. When in doubt, revoke and replace; it costs minutes, and a leaked key costs a great deal more.

Sources

  1. OWASP Cheat Sheet Series: Secrets Management Cheat Sheet (accessed 2026-09-12)