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
ptracerights, and any process withptracecan already read all memory; others counter that on default systems same-UIDptraceis 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_secretand FIFOs/pipes where secrets never hit disk or long-lived env.
- Permissioned files (e.g. config files,
- 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: avoidsetenvin libraries; useexecveto set env for children.- There’s discussion of
getenv_r, tracing env access (e.g., Node’s--trace-env), and theARG_MAX“argument list too long” limit, withxargsas 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.