skills/insecure-defaults-anti-pattern/SKILL.md
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.
npx skillsauth add igbuend/grimbard insecure-defaults-anti-patternInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Severity: Critical
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.
Never provide fallback values for security-critical configuration. Applications should fail immediately (fail-secure) when required secrets or security settings are missing.
| Pattern | Behavior | Risk | |---------|----------|------| | Fail-open (BAD) | Uses default when config missing | Silent security bypass | | Fail-secure (GOOD) | Crashes when config missing | Deployment fails safely |
# VULNERABLE: Fail-open - application runs with weak defaults
import os
import jwt
# 1. Default secret when environment variable is missing
SECRET_KEY = os.environ.get("SECRET_KEY", "default-secret-change-me")
# 2. Debug mode defaults to enabled
DEBUG = os.environ.get("DEBUG", "true").lower() == "true"
# 3. Weak algorithm fallback
JWT_ALGORITHM = os.environ.get("JWT_ALGORITHM", "HS256") # Should require RS256
def create_token(user_id):
# Runs with weak secret if SECRET_KEY not set
return jwt.encode({"user_id": user_id}, SECRET_KEY, algorithm=JWT_ALGORITHM)
def verify_token(token):
# Attacker can forge tokens using "default-secret-change-me"
return jwt.decode(token, SECRET_KEY, algorithms=[JWT_ALGORITHM])
// VULNERABLE: Node.js fail-open patterns
const express = require('express');
const session = require('express-session');
const app = express();
// 1. Session secret with insecure default
app.use(session({
secret: process.env.SESSION_SECRET || 'keyboard cat', // Fail-open!
resave: false,
saveUninitialized: true
}));
// 2. CORS defaults to permissive
const corsOrigin = process.env.CORS_ORIGIN || '*'; // Allows all origins!
// 3. Rate limiting disabled by default
const rateLimit = process.env.RATE_LIMIT || 0; // 0 = unlimited
# SECURE: Fail-secure - application crashes if config missing
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
# 1. No default - must be configured
SECRET_KEY = get_required_env("SECRET_KEY")
# 2. Debug defaults to disabled (safe default)
DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
# 3. Validate algorithm is secure
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)
// SECURE: Node.js fail-secure patterns
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();
// 1. Session secret required - no default
app.use(session({
secret: requireEnv('SESSION_SECRET'),
resave: false,
saveUninitialized: false, // Also secure default
cookie: { secure: true } // Require HTTPS
}));
// 2. CORS must be explicitly configured
const corsOrigin = requireEnv('CORS_ORIGIN');
if (corsOrigin === '*') {
console.error('FATAL: CORS_ORIGIN cannot be wildcard in production');
process.exit(1);
}
// 3. Rate limiting with secure default
const rateLimit = parseInt(process.env.RATE_LIMIT || '100', 10);
Go:
// VULNERABLE: Fail-open defaults
func getConfig() Config {
return Config{
// Default secret if not set
JWTSecret: getEnvOrDefault("JWT_SECRET", "development-secret"),
// Debug enabled by default
Debug: getEnvOrDefault("DEBUG", "true") == "true",
// Permissive CORS
CORSOrigin: getEnvOrDefault("CORS_ORIGIN", "*"),
}
}
// SECURE: Fail-secure - panic on missing required config
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", // Defaults to false
CORSOrigin: corsOrigin,
}
}
Java/Spring Boot:
// VULNERABLE: application.properties with insecure defaults
// jwt.secret=${JWT_SECRET:default-secret-do-not-use}
// cors.allowed-origins=${CORS_ORIGINS:*}
// debug.enabled=${DEBUG:true}
// SECURE: Require configuration, no insecure defaults
@Configuration
public class SecurityConfig {
@Value("${jwt.secret}") // No default - fails if missing
private String jwtSecret;
@Value("${cors.allowed-origins}") // No default
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");
}
}
}
Search for fallback patterns in configuration code:
# Python: os.environ.get with default values for secrets
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'
development
Security anti-pattern for Cross-Site Scripting vulnerabilities (CWE-79). Use when generating or reviewing code that renders HTML, handles user input in web pages, uses innerHTML/document.write, or builds dynamic web content. Covers Reflected, Stored, and DOM-based XSS. AI code has 86% XSS failure rate.
development
Security anti-pattern for XPath injection vulnerabilities (CWE-643). Use when generating or reviewing code that queries XML documents, constructs XPath expressions, or handles user input in XML operations. Detects unescaped quotes and special characters in XPath queries.
development
Security anti-pattern for weak password hashing (CWE-327, CWE-759). Use when generating or reviewing code that stores or verifies user passwords. Detects use of MD5, SHA1, SHA256 without salt, or missing password hashing entirely. Recommends bcrypt, Argon2, or scrypt.
development
Security anti-pattern for weak encryption (CWE-326, CWE-327). Use when generating or reviewing code that encrypts data, handles encryption keys, or uses cryptographic modes. Detects DES, ECB mode, static IVs, and custom crypto implementations.