| name | insecure-defaults-anti-pattern |
| description | Security anti-pattern for fail-open defaults (CWE-1188). Use when reviewing code that uses fallback values for secrets, credentials, or security settings. Detects applications that run with weak defaults when configuration is missing. |
| aliases | ["fail-open","default-secrets"] |
Insecure Defaults Anti-Pattern
Severity: Critical
Summary
Insecure defaults occur when applications continue operating with weak or default values when required configuration is missing. Unlike hardcoded secrets (which are always present), insecure defaults create fail-open conditions where missing environment variables cause the application to silently use unsafe fallback values. This is particularly dangerous because the vulnerability only manifests in misconfigured deployments.
The Anti-Pattern
Never provide fallback values for security-critical configuration. Applications should fail immediately (fail-secure) when required secrets or security settings are missing.
Key Distinction
| Pattern | Behavior | Risk |
|---|
| Fail-open (BAD) | Uses default when config missing | Silent security bypass |
| Fail-secure (GOOD) | Crashes when config missing | Deployment fails safely |
BAD Code Examples
import os
import jwt
SECRET_KEY = os.environ.get("SECRET_KEY", "default-secret-change-me")
DEBUG = os.environ.get("DEBUG", "true").lower() == "true"
JWT_ALGORITHM = os.environ.get("JWT_ALGORITHM", "HS256")
def create_token(user_id):
return jwt.encode({"user_id": user_id}, SECRET_KEY, algorithm=JWT_ALGORITHM)
def verify_token(token):
return jwt.decode(token, SECRET_KEY, algorithms=[JWT_ALGORITHM])
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
secret: process.env.SESSION_SECRET || 'keyboard cat',
resave: false,
saveUninitialized: true
}));
const corsOrigin = process.env.CORS_ORIGIN || '*';
const rateLimit = process.env.RATE_LIMIT || 0;
GOOD Code Examples
import os
import sys
import jwt
def get_required_env(name):
"""Get required environment variable or exit."""
value = os.environ.get(name)
if not value:
sys.exit(f"FATAL: Required environment variable {name} is not set")
return value
SECRET_KEY = get_required_env("SECRET_KEY")
DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
JWT_ALGORITHM = os.environ.get("JWT_ALGORITHM", "RS256")
if JWT_ALGORITHM not in ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512"]:
sys.exit(f"FATAL: Insecure JWT algorithm: {JWT_ALGORITHM}")
def create_token(user_id):
return jwt.encode({"user_id": user_id}, SECRET_KEY, algorithm=JWT_ALGORITHM)
const express = require('express');
const session = require('express-session');
function requireEnv(name) {
const value = process.env[name];
if (!value) {
console.error(`FATAL: Required environment variable ${name} is not set`);
process.exit(1);
}
return value;
}
const app = express();
app.use(session({
secret: requireEnv('SESSION_SECRET'),
resave: false,
saveUninitialized: false,
cookie: { secure: true }
}));
const corsOrigin = requireEnv('CORS_ORIGIN');
if (corsOrigin === '*') {
console.error('FATAL: CORS_ORIGIN cannot be wildcard in production');
process.exit(1);
}
const rateLimit = parseInt(process.env.RATE_LIMIT || '100', 10);
Language-Specific Examples
Go:
func getConfig() Config {
return Config{
JWTSecret: getEnvOrDefault("JWT_SECRET", "development-secret"),
Debug: getEnvOrDefault("DEBUG", "true") == "true",
CORSOrigin: getEnvOrDefault("CORS_ORIGIN", "*"),
}
}
func getConfig() Config {
jwtSecret := os.Getenv("JWT_SECRET")
if jwtSecret == "" {
log.Fatal("FATAL: JWT_SECRET environment variable required")
}
corsOrigin := os.Getenv("CORS_ORIGIN")
if corsOrigin == "" || corsOrigin == "*" {
log.Fatal("FATAL: CORS_ORIGIN must be explicitly set (not wildcard)")
}
return Config{
JWTSecret: jwtSecret,
Debug: os.Getenv("DEBUG") == "true",
CORSOrigin: corsOrigin,
}
}
Java/Spring Boot:
@Configuration
public class SecurityConfig {
@Value("${jwt.secret}")
private String jwtSecret;
@Value("${cors.allowed-origins}")
private String corsOrigins;
@PostConstruct
public void validateConfig() {
if (jwtSecret == null || jwtSecret.length() < 32) {
throw new IllegalStateException("jwt.secret must be at least 32 characters");
}
if ("*".equals(corsOrigins)) {
throw new IllegalStateException("cors.allowed-origins cannot be wildcard");
}
}
}
Detection
Search for fallback patterns in configuration code:
rg 'environ\.get\([^)]+,\s*["\'][^"\']+["\']' --type py
# JavaScript: process.env with || fallback
rg 'process\.env\.\w+\s*\|\|' --type js --type ts
# Go: getEnvOrDefault patterns
rg 'getEnv.*Default|Getenv.*""' --type go
# Generic: Common insecure default strings
rg -i '(secret|key|password|token).*default|change.?me|keyboard.?cat|development'
What to Ignore (Not Vulnerabilities)
- Test directories and spec files
- Example/sample/template files
- Development-only configurations (docker-compose.dev.yml)
- Documentation and README files
- Build-time placeholders replaced during deployment
- Fail-secure patterns that crash on missing config
Prevention
Related Anti-Patterns
References