An application that silently starts without a required environment variable will either crash at the specific moment the missing config is first used — mid-request, during a payment, or at checkout — or it will fall back to an undefined value and behave incorrectly without any error. OWASP A05 (Security Misconfiguration) covers misconfigured applications that fail silently. CWE-390 (Detection of Error Condition Without Action) applies when missing configuration is neither detected nor surfaced. Startup validation converts a runtime surprise into a deployment-time failure, where it is cheap to catch and easy to diagnose.
Low because missing startup validation causes runtime failures at the point of use rather than at startup, making configuration errors harder to diagnose and increasing MTTR for deployment issues.
Add a validation module that imports before any application logic and throws a descriptive error listing every missing variable. Import it as the first line of your server entry point.
// src/config.ts
const required = [
'DATABASE_URL',
'STRIPE_SECRET_KEY',
'JWT_SECRET',
'NEXTAUTH_SECRET',
] as const
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`)
}
}
export const config = {
databaseUrl: process.env.DATABASE_URL!,
stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
jwtSecret: process.env.JWT_SECRET!,
} satisfies Record<string, string>
// src/server.ts — first import
import './config' // validation runs immediately on module load
For Next.js, place this in src/lib/env.ts and import from both next.config.ts and any server-side entry point.
ID: environment-security.configuration-security.env-validation
Severity: low
What to look for: Check the main entry point (server.ts, index.ts, app.ts, next.config.ts) for environment variable validation. Look for checks like if (!process.env.DATABASE_URL) throw new Error(...).
Pass criteria: Count all required environment variable references across the codebase. The application validates at least 100% of required environment variables at startup and fails with a clear error message if any are missing.
Cross-reference: For environment separation concerns, see the env-separation check in the Secrets Management category.
Fail criteria: No validation of required env vars, or validation happens only at runtime when a specific feature is used (not at startup).
Skip (N/A) when: Never — all applications should validate required config at startup.
Detail on fail: "No validation of required environment variables at startup" or "DATABASE_URL validation only happens when database is first accessed, not at app start".
Remediation: Add startup validation:
// src/config.ts
const requiredVars = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET']
for (const varName of requiredVars) {
if (!process.env[varName]) {
throw new Error(`Required environment variable ${varName} is not set`)
}
}
export const config = {
DATABASE_URL: process.env.DATABASE_URL!,
API_KEY: process.env.API_KEY!,
JWT_SECRET: process.env.JWT_SECRET!,
}
// src/server.ts (first line)
import './config' // validation runs on import