SecurityMarch 3, 20267 min read

Stop Committing .env Files: How to Sync Secrets Securely

Millions of secrets leak on GitHub every year. Learn how to sync environment files across machines without ever risking exposure.

The Problem with .env Files

Every modern application uses environment variables for configuration: API keys, database credentials, third-party tokens, encryption secrets. These typically live in .env files at the root of your project. They are essential for development, and they are a ticking time bomb.

GitGuardian's 2025 State of Secrets Sprawl report found over 12.8 million new secrets exposed in public GitHub repositories in a single year — a 28% increase over the previous year. And those are just the public repos. The actual number including private repos, Slack messages, and shared documents is far higher.

The consequences are real. Exposed AWS keys have led to crypto-mining bills exceeding $50,000. Leaked database credentials have caused data breaches. Compromised API tokens have resulted in account takeovers. A single committed .env file can undo months of careful security work.

Why Existing Approaches Fail

.gitignore is not enough. Yes, you should always have .env in your .gitignore. But .gitignore only prevents future commits. If a .env file was ever committed — even once, even accidentally, even if you immediately removed it — the secrets are in the git history forever. Running git rm does not delete it from previous commits. And force-pushing to rewrite history does not remove it from forks or anyone who has already pulled.

Sharing via Slack or email is insecure. When a new developer joins the team, how do they get the .env file? In most teams, someone copies and pastes it into Slack or sends it by email. Those messages persist in company logs, search indexes, and message retention policies. Secrets shared this way have an indefinite exposure window.

Cloud drives are not encrypted for this. Storing .env files in Google Drive or Dropbox might seem convenient, but these services are not designed for secrets management. Files are stored in plain text, synced to multiple devices, and often indexed for search. A compromised account exposes everything.

The core problem: developers need to share and sync secrets across machines, but every common method for doing so creates a permanent record of those secrets in a system that was not designed to protect them.

The Solution: Encrypted Sync with ConfigSync

ConfigSync solves this by treating .env files as first-class encrypted artifacts. Secrets are encrypted on your machine before they ever leave it, synced through an encrypted cloud vault, and decrypted only on your authenticated devices.

Add and push .env files
# Track a project's .env file $ configsync add env ~/git/myapp Added ~/git/myapp/.env to env module. # Push to encrypted cloud vault $ configsync push --filter env Encrypting .env files... ✓ ~/git/myapp/.env (AES-256-GCM, encrypted) ✓ ~/git/api-service/.env (AES-256-GCM, encrypted) ✓ ~/git/api-service/.env.local (AES-256-GCM, encrypted) Pushed 3 encrypted env files.

On another machine, pulling restores the files with correct permissions:

Pull .env files on another machine
# Preview what will be restored $ configsync pull --filter env --dry-run Would restore: ~/git/myapp/.env (0600 permissions) ~/git/api-service/.env (0600 permissions) ~/git/api-service/.env.local (0600 permissions) # Restore for real $ configsync pull --filter env Restored 3 env files (decrypted, permissions set to 0600).

How the Encryption Works

ConfigSync uses AES-256-GCM encryption, the same standard used by banks and government agencies. Here is what happens when you push a .env file:

  1. Your master password is used to derive an encryption key via PBKDF2 with a unique per-file salt. The master password never leaves your machine.
  2. Each file is encrypted with its own randomly generated nonce. Even identical files produce different ciphertext.
  3. The encrypted data is uploaded to ConfigSync's cloud vault (Cloudflare R2). The server only ever sees encrypted bytes.
  4. On pull, the encrypted data is downloaded and decrypted locally using your master password. File permissions are set to 0600 (owner read/write only).

This is zero-knowledge encryption. ConfigSync's servers cannot read your secrets. Even if the cloud storage were compromised, attackers would get only encrypted data with no way to decrypt it.

Environment-Scoped Secrets

Most projects have different secrets per environment: development, staging, production. ConfigSync supports scoped .env files so you can track and sync them separately:

Scoped environment files
# Track environment-specific files $ configsync add env ~/git/myapp --scope dev $ configsync add env ~/git/myapp --scope staging # Push only staging secrets $ configsync push --filter env:staging # Pull dev secrets on your dev machine $ configsync pull --filter env:dev

This prevents accidentally pulling production credentials onto a development machine or overwriting staging secrets with local values. Each scope is encrypted independently and can be synced to different machines.

Secret Providers: Integrating with Your Existing Vault

ConfigSync's built-in encrypted vault is the default, but you can also integrate with external secret providers for teams that already use a centralized secret manager:

ProviderHow It WorksBest For
Built-in vaultAES-256-GCM encrypted, synced via R2Individual developers, small teams
1PasswordReads/writes secrets via 1Password CLITeams already using 1Password
BitwardenReads/writes via Bitwarden CLITeams using Bitwarden
OS KeychainmacOS Keychain / Linux secret-serviceMachine-specific secrets
Using 1Password as a provider
# Configure 1Password as your secret provider $ configsync config set secrets.provider 1password $ configsync config set secrets.1password.vault "Development" # Secrets are now stored in your 1Password vault $ configsync push --filter env Pushed 3 env files to 1Password vault "Development".

inject_as_env: Never Write Secrets to Disk

For maximum security, ConfigSync can inject environment variables directly into a process without ever writing a .env file to disk. This eliminates the risk of secrets being read from the filesystem by other processes, included in backups, or accidentally committed:

Inject secrets directly into a process
# Run your app with secrets injected, no .env file needed $ configsync inject --project myapp -- npm run dev Injecting 12 environment variables... > next dev ready - started server on 0.0.0.0:3000 # The .env file never touches the filesystem. # Secrets exist only in the process's environment.
With inject_as_env, there is literally no .env file to commit, leak, or share insecurely. Secrets go straight from the encrypted vault into your running process's memory.

A Better Workflow for Teams

Combining ConfigSync with your existing security practices creates a workflow where secrets are always encrypted, never shared through insecure channels, and automatically available on authorized machines:

  1. Secrets are added once via configsync add env and encrypted locally.
  2. Encrypted secrets sync to the cloud vault or your team's password manager.
  3. New team members run configsync pull after authentication to get secrets.
  4. Secret rotation is a push/pull cycle — no Slack messages, no shared documents.
  5. Audit logs track who accessed which secrets and when.

No more pasting API keys in Slack. No more "can someone send me the .env file?" messages. No more accidentally committing secrets and scrambling to rotate them.

Get Started in 2 Minutes

Secure your .env files now
$ npm install -g configsync $ configsync login $ configsync add env ~/git/my-project $ configsync push --filter env Done. Your secrets are encrypted and synced.

Ready to try ConfigSync?

Sync your entire dev environment across machines in minutes. Free forever for up to 3 devices.