← All writing

Blog

Why Your .env Secrets Shouldn't Be Plaintext on Disk

Why plaintext .env files are a prime target for supply-chain attacks, and how dotsecenv keeps developer secrets encrypted at rest with GPG.

Photo: encrypted secrets on disk
Photo by Clint Patterson on Unsplash

The Trivy/TeamPCP Supply Chain Attack

On March 19, 2026, a threat actor known as TeamPCP compromised Aqua Security’s Trivy vulnerability scanner in a supply chain attack (CVE-2026-33634). The malicious code swept 50+ filesystem locations on CI/CD runners, harvesting SSH keys, AWS/GCP/Azure credentials, .env files, database passwords, Docker configs, and Kubernetes tokens. It then dumped Runner.Worker process memory to extract additional secrets.

The damage didn’t stop there. Credentials stolen from CI/CD pipelines cascaded downstream — within days, TeamPCP used harvested PyPI tokens to backdoor LiteLLM, an AI gateway library with ~3.4 million daily downloads. The compromised versions deployed a three-stage payload: credential harvesting, Kubernetes lateral movement, and a persistent backdoor for remote code execution. Other projects were also targeted in the same campaign.

This wasn’t an isolated pattern. In August 2024, Palo Alto’s Unit 42 documented an extortion campaign that found exposed .env files on 110,000+ domains and stole 90,000+ environment variables. GitHub’s own data shows 39 million secrets were committed to public repositories in 2024 alone.

The pattern is consistent: plaintext secrets on disk are a high-value, low-effort target.

The Gap in Existing Tools

Several tools address parts of this problem, and they’re all good at what they do:

SOPS encrypts config files in-place and supports cloud KMS backends (AWS, GCP, Azure). It’s excellent for production config management. But it has no shell integration for developer workflows, and multi-user key sharing requires manual .sops.yaml configuration.

direnv provides the shell integration developers want — environment variables load automatically when you cd into a project. But it provides zero encryption. Your secrets are still plaintext in .envrc.

HashiCorp Vault, Doppler, Infisical are powerful platforms with dynamic secrets, rotation, and web dashboards. They’re the right choice for production. But they require server infrastructure or SaaS accounts — overhead that doesn’t make sense when a developer just needs to share an API key with a teammate.

git-crypt encrypts files transparently in git, but operates at the file level with no per-secret granularity and no sharing workflow.

The gap: no tool combines encryption at rest, shell auto-loading, and simple multi-user sharing without requiring a server or cloud account.

Enter dotsecenv

I’ve been building this on and off since last December. I wanted my secrets encrypted at rest and a simple way to share them across my machines without relying on any external services.

dotsecenv is a Go CLI tool that encrypts environment secrets at rest using hybrid encryption: AES-256-GCM for data and GPG for key exchange. Secrets are stored in a vault file that’s safe to commit to git. However, that is purely optional — you don’t actually have to commit the vault.

# Store a secret (encrypted in the vault)
echo "my-api-key" | dotsecenv secret store API_KEY

# Retrieve it (decrypted on-demand via GPG)
dotsecenv secret get API_KEY

# Share with a teammate (their GPG public key)
dotsecenv secret share API_KEY [email protected]

A shell plugin for zsh, bash, and fish decrypts and loads secrets when you enter a directory — like direnv, but your secrets stay encrypted on disk:

# .secenv file (safe to commit)
API_KEY={dotsecenv}
DATABASE_PASSWORD={dotsecenv}

# cd into the project directory, secrets load automatically
cd my-project/
echo $API_KEY # decrypted on-demand

Why GPG?

GPG over age was a tradeoff — age is simpler, but I needed signatures for tamper detection and audit trails. Signatures enable:

  • Verifying who created each secret: every vault entry is signed by the originator’s key
  • Tamper detection: dotsecenv validate checks cryptographic integrity
  • Non-repudiation: audit trails with provable authorship

Plus, most developers already have a GPG key from GitHub or GitLab commit signing. dotsecenv builds on that existing infrastructure. If, however, you don’t have a GPG key, you can generate one with dotsecenv identity create without getting into the GPG nitty-gritty!

Algorithm defaults align with FIPS 186-5 (Ed25519, ECDSA P-384, RSA-3072+), and the tool refuses to operate with weaker algorithms.

What dotsecenv Does NOT Protect Against

I want to be upfront about the boundaries:

  • Process memory: once secrets are loaded as environment variables, they’re readable via /proc or memory dumps. The Trivy attack also dumped Runner.Worker process memory; encryption at rest doesn’t help there.
  • Compromised GPG private key: if your private key is stolen and unprotected, your secrets are exposed.
  • Root/admin access: a privileged attacker can read anything.
  • Production runtime: dotsecenv targets the development lifecycle (SDLC), not production secret injection. For production, use Vault, AWS Secrets Manager, or a similar service.

dotsecenv is defense-in-depth — it eliminates the plaintext-on-disk attack surface. If the Trivy attacker’s disk sweep had found GPG ciphertext instead of plaintext .env files, that component of the attack would have yielded nothing usable, or at the very least made the exfiltration much harder to effect. The LiteLLM cascade — where a single set of stolen plaintext credentials led to the compromise of a library with millions of daily downloads — illustrates exactly why encryption at rest matters at every stage of the supply chain.

Current State

dotsecenv is functional, and I use it daily. It has:

There are rough edges. Windows support is WIP. The vault format may evolve. I aim to provide migration tooling for any breaking changes, though this may not always be feasible. I’m looking for feedback from developers who deal with secrets in their daily workflow — if you try it out and have feedback, please open an issue on GitHub!

Join the Conversation

This post is being discussed on Hacker News. If you have thoughts, questions, or war stories about managing secrets in development workflows, I’d love to hear them — jump into the thread and let’s talk.

Further Reading on the Trivy/TeamPCP Campaign

Ready to encrypt your .env files?

Thank you for reading! 🙏

This article is also published on Medium .