Safeguard
Application Security•

CWE-526 Cleartext Secrets in Environment Variables: Risks and Fixes

Environment variables are handy for secrets and easy to leak through debug pages, logs and child processes. Three real CVEs and how to store secrets better.

Safeguard Security Team
4 min read

CWE-526 is a product that uses an environment variable to store unencrypted sensitive information. It is not tied to a language, and it is common in cloud and CI setups.

Twelve factor style guides push configuration into the environment, so API keys and database passwords end up there. The weakness is that the environment is wider than it looks.

How it happens

MITRE explains that information in an environment variable can be reached by other processes in the same execution context, including child processes where dependencies run, or serverless functions in the cloud. Those processes often have no need for the variable. Its contents can also be inserted into messages, headers, log files or other output, so any weakness that discloses environment variables exposes the secret.

The record lists three examples.

  • CVE-2022-43691: a CMS shows sensitive server side information from environment variables when run in debug mode.
  • CVE-2022-27195: a plugin for an automation server inserts environment variable contents into build XML files.
  • CVE-2022-25264: a CI/CD tool logs environment variables related to passwords, which are then added to content history.

Different tools, same cause. A secret in the environment travels wherever the environment is printed, copied or inherited.

# Risky patterns
import os, subprocess
db_password = os.environ["DB_PASSWORD"]            # secret lives in the environment

subprocess.run(["some-tool"])                      # child inherits every variable

print(dict(os.environ))                            # debug line that dumps them all

What an attacker gains

MITRE lists reading application data. A leaked environment can hand over database credentials, cloud keys and tokens. From there the attacker can act as the application, and each secret may open further systems.

How to find it

Automated static analysis can find some instances by following reads from the environment and the places they end up.

  • Search code and deployment files for secrets passed as environment variables: Dockerfiles with ENV, compose files, CI settings, serverless config.
  • Search for code that prints, logs or serializes the whole environment, such as os.environ, process.env or printenv in scripts.
  • Check what debug modes and error pages show. Make sure they are off in production.
  • Check build logs for values that look like secrets.
  • Run a secrets scan over repositories and images, since Dockerfile ENV lines are stored in the image.

How to fix it

MITRE's guidance has two parts.

  1. At design time, encrypt information kept in the environment variable. If that is not practical, use a properly protected configuration file instead. MITRE notes that an unencrypted config file is not guaranteed safe either, but it is still a better choice because it reduces the attack surface from related weaknesses such as CWE-214. In some settings, vaults may be a workable way to deliver secrets more safely. Users should be told when the business chooses not to encrypt.
  2. At implementation time, if the variable is not needed for the behavior, remove it or set it to an empty value.

Practical habits:

  • Fetch secrets from a vault or secrets manager at start up, and keep them in memory only as long as needed.
  • Pass a child process only the variables it needs, with a clean environment.
  • Never log or print the whole environment. Mask known secret names in CI output.
  • Keep secrets out of image layers and build arguments.
  • Turn off debug pages in production.
import subprocess
clean_env = {"PATH": "/usr/bin:/bin", "LANG": "C"}      # only what the tool needs
subprocess.run(["some-tool"], env=clean_env)

Try it yourself

Click through it at your own pace, or open it full screen.

Quick check

Why are environment variables leaky?

Child processes inherit them, and tools or debug pages often print them into logs, headers and files.

What does MITRE suggest if encryption is not practical?

A properly protected configuration file, or a vault where feasible. Or remove the variable if it is not needed.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.