Skip to main content
Security skill for detecting insecure default configurations that create vulnerabilities when applications run with missing or incomplete configuration. Focuses on fail-open patterns where apps run insecurely rather than crash safely.

Overview

The insecure-defaults plugin identifies security vulnerabilities caused by dangerous default values that allow applications to run in production with weak or missing security controls. It distinguishes between fail-secure patterns (app crashes) and fail-open patterns (app runs insecurely).
Author: Trail of Bits
Version: 1.0.0
Critical Distinction: Applications that crash without proper configuration are safe (fail-secure). Applications that run with insecure defaults are vulnerable (fail-open).

Vulnerability Categories

The plugin detects five categories of insecure defaults:

Hardcoded Fallback Secrets

JWT keys, API keys, session secrets with fallback values

Default Credentials

admin/admin, root/password, test API keys

Weak Cryptographic Defaults

MD5, DES, ECB mode for security-sensitive operations

Permissive Access Control

CORS *, public by default, world-writable permissions

Missing Security Configuration

Authentication disabled by default, debug mode enabled

When to Use

Use this skill when:
  • Security auditing production applications or services
  • Configuration review of deployment manifests (Docker, Kubernetes, IaC)
  • Pre-production checks before deploying new services
  • Code review of authentication, authorization, or cryptographic code
  • Environment variable handling analysis for secrets management
  • API security review checking CORS, rate limiting, authentication
  • Third-party integration review for hardcoded test credentials

When NOT to Use

Do not use this skill for:
  • Test fixtures explicitly scoped to test environments (test/, spec/, __tests__/)
  • Example/template files (.example, .template, .sample suffixes)
  • Development-only tools (local Docker Compose for dev, debug scripts)
  • Documentation examples in README.md or docs/ directories
  • Build-time configuration that gets replaced during deployment
  • Crash-on-missing behavior where app won’t start without proper config (fail-secure)
When in doubt: trace the code path to determine if the app runs with the default or crashes.

Installation

/plugin install insecure-defaults

Workflow

Follow this workflow for every potential finding:
1

SEARCH: Project Discovery

Determine language, framework, and project conventions. Find secret storage locations, credentialed integrations, cryptography usage, and security configuration.
2

VERIFY: Actual Behavior

Trace code paths to understand runtime behavior. Determine what happens if configuration is missing.
3

CONFIRM: Production Impact

Check if production config provides the variable or if the insecure default reaches production.
4

REPORT: With Evidence

Document location, pattern, verification results, production impact, and exploitation scenario.

Category 1: Fallback Secrets

Vulnerable Patterns

# File: src/auth/jwt.py
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key-123')

# Used in security context
def create_token(user_id):
    return jwt.encode({'user_id': user_id}, SECRET_KEY, algorithm='HS256')
Why vulnerable: App runs with known secret if env var is missing. Attacker can forge tokens/access database.

Secure Patterns

# File: src/auth/jwt.py
SECRET_KEY = os.environ['SECRET_KEY']  # Raises KeyError if missing

# App won't start without SECRET_KEY - fail-secure

Category 2: Default Credentials

Vulnerable Patterns

# File: src/models/user.py
def bootstrap_admin():
    """Create default admin account if none exists"""
    if not User.query.filter_by(role='admin').first():
        admin = User(
            username='admin',
            password=hash_password('admin123'),
            role='admin'
        )
        db.session.add(admin)
        db.session.commit()
Why vulnerable: Default admin accounts or test credentials reach production if env vars missing.

Secure Patterns

Disabled default account
# File: src/models/user.py
def bootstrap_admin():
    """Admin account MUST be configured via environment"""
    username = os.environ['ADMIN_USERNAME']
    password = os.environ['ADMIN_PASSWORD']

    if not User.query.filter_by(username=username).first():
        admin = User(username=username, password=hash_password(password), role='admin')
        db.session.add(admin)

Category 3: Fail-Open Security

Vulnerable Patterns

# File: config/security.py
REQUIRE_AUTH = os.getenv('REQUIRE_AUTH', 'false').lower() == 'true'

@app.before_request
def check_auth():
    if not REQUIRE_AUTH:
        return  # Skip auth check
    # ... auth logic
Why vulnerable: Default is insecure. App runs without authentication, accepts requests from any origin, or leaks stack traces if env var missing.

Secure Patterns

# File: config/security.py
REQUIRE_AUTH = os.getenv('REQUIRE_AUTH', 'true').lower() == 'true'  # Default: true

# Or better - crash if not explicitly configured
REQUIRE_AUTH = os.environ['REQUIRE_AUTH'].lower() == 'true'

Category 4: Weak Crypto

Vulnerable Patterns

# File: src/auth/passwords.py
import hashlib

def hash_password(password):
    """Hash user password"""
    return hashlib.md5(password.encode()).hexdigest()
Why vulnerable:
  • MD5 is cryptographically broken, rainbow tables exist
  • DES has 56-bit keys (brute-forceable), ECB mode leaks patterns
  • SHA1 collisions exist
Use bcrypt/Argon2 for passwords, AES-GCM for encryption, SHA256+ for signatures.

Secure Patterns

# File: src/auth/passwords.py
import bcrypt

def hash_password(password):
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt())
Weak crypto for non-security checksums (cache keys, ETags) is acceptable.

Category 5: Permissive Access

Vulnerable Patterns

# File: src/storage/files.py
def create_secure_file(path):
    fd = os.open(path, os.O_CREAT | os.O_WRONLY, 0o666)  # rw-rw-rw-
    return fd
Why vulnerable:
  • Any user can write to file (should be 0o600 or 0o644)
  • Sensitive data exposed publicly
  • CORS misconfiguration allows credential theft from any site

Search Patterns

Use these grep patterns to discover insecure defaults:
grep -r "getenv.*\) or ['\"]" **/config/ **/auth/
grep -r "process\.env\.[A-Z_]+ \|\| ['\"]" src/
grep -r "ENV\.fetch.*default:" config/
grep -r "password.*=.*['\"][^'\"]{8,}['\"]" src/
grep -r "api[_-]?key.*=.*['\"][^'\"]+['\"]" config/
grep -r "secret.*=.*['\"][^'\"]+['\"]" --include="*.py" --include="*.js"
grep -r "DEBUG.*=.*true" config/
grep -r "AUTH.*=.*false" src/
grep -r "CORS.*=.*\*" server/
grep -r "MD5\|SHA1\|DES\|RC4\|ECB" src/auth/ src/crypto/

Rationalizations to Reject

Reject these shortcuts that lead to missed findings:
RationalizationWhy It’s Wrong
”It’s just a development default”If it reaches production code, it’s a finding
”The production config overrides it”Verify prod config exists; code-level vulnerability remains
”This would never run without proper config”Prove it with code trace; many apps fail silently
”It’s behind authentication”Defense in depth; compromised session still exploits weak defaults
”We’ll fix it before release”Document now; “later” rarely comes

Report Format

For each finding, document:
Finding: Hardcoded JWT Secret Fallback
Location: src/auth/jwt.ts:15
Pattern: const secret = process.env.JWT_SECRET || 'default';

Verification: App starts without JWT_SECRET; secret used in jwt.sign() at line 42
Production Impact: Dockerfile missing JWT_SECRET
Exploitation: Attacker forges JWTs using 'default', gains unauthorized access

Severity: CRITICAL

Build docs developers (and LLMs) love