Flat .env files synced to servers are a single point of compromise: one leaked file, one misconfigured S3 bucket, or one server breach exposes every production credential at once. Dedicated secrets managers — AWS Secrets Manager, HashiCorp Vault, Azure Key Vault — provide access control per secret, audit logs of every retrieval, automatic rotation, and versioned history. OWASP A05 (Security Misconfiguration) and NIST SC-12 both require protecting the integrity of keys and credentials throughout their lifecycle. PCI-DSS 4.0 Req-3.5 mandates protecting stored credentials, which flat files cannot satisfy for any cardholder data environment.
High because flat .env files on servers have no per-secret access control or audit trail, making breach detection and targeted rotation impossible when any one credential is exposed.
Replace flat .env.production files with a secrets manager appropriate to your hosting platform. Pull secrets at startup so no plaintext credentials ever land on disk.
AWS Secrets Manager:
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
const client = new SecretsManagerClient({ region: 'us-east-1' })
const { SecretString } = await client.send(
new GetSecretValueCommand({ SecretId: 'prod/stripe-key' })
)
HashiCorp Vault:
import vault from 'node-vault'
const client = vault({ endpoint: process.env.VAULT_ADDR, token: process.env.VAULT_TOKEN })
const { data } = await client.read('secret/data/prod/stripe-key')
After migrating, delete the .env.production file from all servers and revoke any credentials it contained.
ID: environment-security.secrets-management.secrets-manager-used
Severity: high
What to look for: Check for evidence of a dedicated secrets manager: AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, Google Secret Manager, or similar. Look for initialization code, dependencies, environment variable references to manager endpoints, or documentation.
Pass criteria: Count all production secret references. Production secrets are stored in a dedicated secrets manager, not in flat .env files -- at least 100% of production secrets must use the manager's API for retrieval.
Fail criteria: Production secrets stored in .env files that are synced to the server, hardcoded in config, or in any flat-file format.
Skip (N/A) when: The project is development-only or a hobby project with no real production secrets (though this is rare).
Detail on fail: Specify the current storage method. Example: "Production secrets stored in .env.production file on server; no secrets manager detected" or "Only using .env files with no secrets manager integration".
Remediation: Set up a secrets manager appropriate to your hosting platform:
AWS: Use AWS Secrets Manager or AWS SSM Parameter Store. Initialize in your app:
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
const secret = await new SecretsManagerClient().send(
new GetSecretValueCommand({ SecretId: 'stripe-key' })
)
HashiCorp Vault: Use Vault for generic secret storage across platforms:
import vault from 'node-vault'
const client = vault({ endpoint: process.env.VAULT_ADDR })
const secret = await client.read('secret/stripe-key')
Azure / GCP: Similar pattern using Azure Key Vault or Google Secret Manager SDKs.