Secret Management with GhostEnv
Published on January 28, 2026
Secret Management with GhostEnv
.env files are one of the biggest vectors for secret leaks in the industry. It’s not theory: bots run 24/7 scanning repositories, commits, and backups for environment variables. Any .env that ends up in Git, in a backup, or in a log can expose API keys, database passwords, and tokens that put the whole system at risk.
That’s why I built GhostEnv: a secure environment variable manager that encrypts secrets and injects them in memory at runtime. It’s written in Go and designed for team workflows too: developers don’t have to see production variables; only the tech lead manages them, and the team can deploy to production without having access to the keys.
In this article I explain the real problem with .env files, why I chose Go for this tool, how GhostEnv works, and how to use it in a secure team workflow.
The problem: .env in plain text
A .env file is plain text. Any process with filesystem access can read it. If it’s committed to Git by mistake, it stays in history. If a backup includes the project, it includes the .env. If someone dumps memory or logs variables, the keys appear in the clear.
Worse: automated bots crawl public repositories (and sometimes commits that were thought to be private), looking for patterns like API_KEY=, DATABASE_URL=, SECRET=, PASSWORD=. When they find something, they index it and sell it or use it for attacks. It’s not paranoia; it happens every day.
The consequences are clear: cloud accounts drained, databases compromised, third-party service tokens revoked, and failed security audits. So secret management can’t be “a file we don’t commit to Git”. It has to be encryption at rest and injection only at runtime for the process that needs it.
Why GhostEnv and why Go
I wanted a tool that:
- Never stores secrets in plain text — not on disk, not in Git.
- Injects variables into the process at runtime, without creating temporary
.envfiles. - Supports secure team workflows: the tech lead or whoever manages infrastructure manages the variables, and the rest of the team can deploy without seeing the keys.
- Works everywhere: cross-platform and compatible with any language or runtime that reads environment variables.
I chose Go for performance, portability, and the ability to ship a single binary with no external runtime. GhostEnv is distributed as an executable; it doesn’t require a runtime to be installed. Go is also a good fit for system tools: process handling, encryption, and filesystem access are well covered in the standard library.
What GhostEnv does
GhostEnv doesn’t replace environment variables; it uses them. The difference is that instead of reading from a plain-text .env file, it reads from encrypted vaults (.gev files) and injects variables directly into the child process environment when you run a command.
Encryption and storage
- Algorithm: AES-256-GCM (authenticated encryption).
- Key derivation: Argon2id (resistant to brute force).
- Files: Each environment (dev, staging, production) can have its own
.gevfile under.ghostenv/in the project. Outside a project, a global vault at~/.ghostenv.gevis used. - Permissions: Vault files are created with restricted permissions (owner read/write only).
- Nothing in plain text: Keys are never written to disk unencrypted.
Runtime injection
When you run:
ghostenv run -- node app.js
GhostEnv decrypts the variables in memory, spawns the child process (node app.js), and injects those variables into its environment. The child process sees process.env.API_KEY, process.env.DATABASE_URL, etc., but no .env file with those values ever existed on disk. It works with Node, Python, Go, Docker, shell scripts, or any binary that uses environment variables.
Per-project environments
You can have different secrets per environment:
# Development (default)
ghostenv set API_KEY "dev-key"
ghostenv run -- npm run dev
# Production (only the tech lead configures these)
ghostenv --env production set API_KEY "prod-key"
ghostenv --env production run -- npm run deploy
Developers can have access only to the dev vault. The production vault is managed only by whoever holds the production master password (e.g. the tech lead or DevOps). That way, the team can deploy to production (by running ghostenv --env production run -- ... in a pipeline or on a server where the password is injected securely, e.g. from the CI/CD secret manager) without developers ever seeing production keys.
Team workflow
- Tech lead / DevOps: Holds the production master password. Configures
ghostenv --env production set ...on the server or in a secure environment, or imports from a.envthat is never committed to Git. Can runghostenv --env production listto see which keys exist (not the values unless they runget). - Developers: Know only the
devpassword (or none if using defaults). They work withghostenv run -- npm run dev. They don’t need to see production variables. - Deployment: In CI/CD you configure a single variable (e.g.
GHOSTENV_PASS) with the production vault password. The pipeline runsghostenv --env production run -- npm run deploy(or whatever command). Variables are injected into memory for that process; no one has to edit.envor see keys in the CI UI.
So developers don’t see the environment variables; only the tech lead (or whoever manages secrets) manages them, and the team can deploy to production without having access to the keys.
Basic usage
Installation (from source with Go installed):
git clone https://github.com/SrPlugin/GhostEnv.git
cd GhostEnv
make build
make install
Quick start:
# Set master password when prompted
ghostenv set API_KEY "your-secret-key"
# Run the app with variables injected
ghostenv run -- node app.js
Import from an existing .env (e.g. one you no longer want in plain text):
ghostenv import .env
# Optional: for production
ghostenv --env production import .env.production
List keys (does not show values):
ghostenv list
ghostenv --env production list
Everything else (multiple environments, export, remove, etc.) is in the project documentation.
Summary of benefits
- No plain-text .env: No files that can leak via Git, backups, or logs.
- Bots and scans: Even if someone gets the repo or a backup, they only see encrypted binary files, not readable keys.
- Team workflow: Tech lead controls production variables; developers deploy without seeing them.
- Language agnostic: Any language that uses environment variables can use GhostEnv.
- Cross-platform: Linux, macOS, and Windows, with a single binary.
My personal perspective
.env leaks aren’t a failure of “one developer who committed the file”. They’re a design failure: continuing to use plain text for secrets when there are tools and practices that avoid exposing them. The bots that scan 24/7 make any .env that touches the internet a real risk.
I built GhostEnv for my own use and for teams that want a simple but serious alternative: strong encryption, in-memory injection, and a clear separation between who manages secrets and who only runs and deploys. It doesn’t replace a corporate secret manager like HashiCorp Vault or AWS Secrets Manager when you already have that infrastructure, but for mid-size projects, startups, or teams that want to stop relying on “don’t commit the .env”, it’s an option that tangibly reduces risk.
If you want to try it or contribute, the project is on GitHub: SrPlugin/GhostEnv. The goal is to keep it focused: one tool, one binary, no runtime dependencies, so you can stop keeping secrets in plain text and work as a team without everyone having to see production keys.