Environment variables are a legacy mess: Let's dive deep into them

Security of environment variables for secrets

  • Many argue env vars are a poor channel for secrets: same-UID processes can usually read each other’s /proc/<pid>/environ, so any tool or plugin running as the user (LLM agents, editors, extensions) can exfiltrate tokens meant for a single script.
  • There’s debate about how bad this is: one side says since 2012 env access effectively requires ptrace rights, and any process with ptrace can already read all memory; others counter that on default systems same-UID ptrace is broadly allowed, so this is still effectively wide-open.
  • Containers somewhat improve isolation (one container can’t see another’s env), but not against a host process, and “containers as security boundary” is treated skeptically.

Alternatives for handling secrets

  • Suggested approaches:
    • Permissioned files (e.g. config files, ~/.ssh, .netrc), sometimes encrypted and decrypted on demand (SOPS, sqlite-based stores).
    • Secret managers (Vault/OpenBao, CyberArk, AWS/GCP secrets, Conjur) accessed via libraries or sidecars; criticized for lock-in and operational fragility (uptime, upgrades).
    • Systemd’s credential system and encrypted credstore; k8s secrets mounted as files or env vars; TPM-backed secrets; TPM/OAuth/IAM to avoid static secrets.
    • Newer primitives like memfd_secret and FIFOs/pipes where secrets never hit disk or long-lived env.
  • Disagreement over whether pointing to a config file (CONFIG_PATH) is actually more secure than env; SELinux and similar can help but are not cross-platform.

Unix security model and isolation

  • Core tension: Unix equates “user account” with “security domain”; many commenters want finer-grained, user-controlled isolation so untrusted tools can’t access all their data.
  • Namespaces and containers are seen as partial, leaky barriers; some recommend real VMs for strong isolation. Others mention seccomp, Landlock, AppArmor/SELinux, Yama, but treat them as mitigations, not cures.

API and implementation quirks

  • setenv() is called fundamentally unsafe on POSIX: getenv() returns raw pointers, so overwriting variables can break other code; some OSes “fix” this by leaking memory instead. Consensus: avoid setenv in libraries; use execve to set env for children.
  • There’s discussion of getenv_r, tracing env access (e.g., Node’s --trace-env), and the ARG_MAX “argument list too long” limit, with xargs as an imperfect workaround.

Configuration UX and philosophy

  • Complaints about the fragmented, non-persistent ways to set env vars on Linux vs Windows’ single GUI; systemd’s /etc/environment(.d) is cited as a partial unifier.
  • Some see env vars-as-config as abuse: they’re global, opaque, typo-prone, and differ across shells, SSH, cron, etc. Others defend them as the simplest, most portable configuration surface, especially for containers.
  • Conceptually, env vars are compared to globals or dynamically scoped variables that hurt determinism; some advocate more hermetic, fully specified runtimes (NixOS, containers) instead.