Initialization of a Resource with an Insecure Default
Description
Initialization of a Resource with an Insecure Default occurs when a product initializes or sets a resource with a default value that is intended to be changed by the product's installer, administrator, or maintainer, but the default is not secure. Developers often prioritize ease-of-use by creating permissive default configurations, assuming administrators will modify them. However, this assumption frequently fails when administrators either overlook the defaults or lack awareness that changes are necessary, leaving the system vulnerable.
Risk
Insecure defaults have significant security implications. Default passwords are commonly exploited by attackers. Permissive access control defaults allow unauthorized access. Debug modes enabled by default expose sensitive information. Insecure default ports or protocols may be used. Default encryption settings may be weak or disabled. Administrative interfaces may be exposed by default. Logging defaults may omit security events. Resource limits may be too permissive. Users assume secure-by-default and don't change settings.
Solution
Apply secure-by-default principles. Require explicit opt-in for less secure configurations. Use strong random defaults for credentials and keys. Default to deny-all access control. Disable debug and test features by default. Use secure protocols by default (HTTPS, TLS). Require password changes on first use. Document all security-relevant defaults clearly. Provide configuration wizards that prompt for secure settings. Log warnings when insecure defaults are in use. Default to minimal functionality.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Varies By Context - The negative effects depend heavily on what functionality the insecure default controls, ranging from information disclosure to complete system compromise. |
| Confidentiality/Integrity/Availability | Scope: All Security Compromise - Insecure defaults in authentication, authorization, or encryption can lead to full system compromise. |
Example Code
Vulnerable Code
// Vulnerable: PHP with register_globals-style vulnerability
// Default allows request parameters to set internal variables
<?php
// $user and $pass automatically set from POST request (old PHP behavior)
// But so is $authorized if attacker includes it in POST!
if (login_user($user, $pass)) {
$authorized = true;
}
if ($authorized) {
// Attacker can bypass by POSTing authorized=true
generateAdminPage();
}
?>
# Vulnerable: Python application with insecure defaults
class DatabaseConfig:
def __init__(self):
# Insecure defaults - should require explicit secure configuration
# Default to no authentication!
self.host = "localhost"
self.port = 5432
self.username = "postgres"
self.password = "" # Empty password by default!
self.ssl_mode = "disable" # SSL disabled by default!
# Permissive connection settings
self.max_connections = 1000 # Too many - DoS risk
self.connection_timeout = 0 # No timeout - resource exhaustion
class AppConfig:
def __init__(self):
# Debug mode on by default - exposes sensitive info
self.debug = True
self.log_level = "DEBUG" # Logs sensitive data
# Weak session defaults
self.session_secret = "change-me" # Known default!
self.session_timeout = 86400 * 30 # 30 days - too long
# Insecure CORS defaults
self.cors_origins = "*" # Allow all origins
# Admin interface exposed by default
self.admin_enabled = True
self.admin_path = "/admin" # Predictable path
class UserDefaults:
# Default admin account with known credentials
ADMIN_USERNAME = "admin"
ADMIN_PASSWORD = "admin123" # Weak, known default password
# Default permissions too permissive
DEFAULT_ROLE = "admin" # Should be "user" or "guest"
// Vulnerable: Java with insecure defaults
public class SecurityConfig {
// Insecure default constructor
public SecurityConfig() {
// Debug enabled by default
this.debugMode = true;
// Weak crypto defaults
this.encryptionAlgorithm = "DES"; // Weak algorithm
this.keySize = 56; // Too small
// Permissive CORS
this.allowedOrigins = Arrays.asList("*");
this.allowCredentials = true; // Dangerous with wildcard origin
// No rate limiting by default
this.maxRequestsPerMinute = Integer.MAX_VALUE;
// Insecure session defaults
this.sessionTimeout = 60 * 60 * 24 * 365; // 1 year!
this.cookieSecure = false; // Sent over HTTP too
this.cookieHttpOnly = false; // Accessible to JS
// Default admin account
this.defaultAdminPassword = "admin";
}
}
// Spring Security with insecure defaults
@Configuration
public class InsecureWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// CSRF disabled by default - bad for web apps
.csrf().disable()
// No authentication required by default
.authorizeRequests()
.anyRequest().permitAll()
// Frame options disabled - clickjacking risk
.and().headers().frameOptions().disable();
}
// Default user with known password
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password("{noop}admin") // Plain text, known password
.roles("ADMIN");
}
}
// Vulnerable: Node.js/Express with insecure defaults
const express = require('express');
const session = require('express-session');
const app = express();
// Insecure session configuration
app.use(session({
secret: 'keyboard cat', // Known default secret!
resave: false,
saveUninitialized: true, // Creates sessions for unauthenticated users
cookie: {
secure: false, // Sent over HTTP
httpOnly: false, // Accessible to JavaScript
maxAge: 1000 * 60 * 60 * 24 * 365 // 1 year!
}
}));
// CORS wide open by default
const cors = require('cors');
app.use(cors()); // Allows ALL origins
// No rate limiting
// No CSRF protection
// No helmet security headers
// Debug info exposed
app.get('/debug', (req, res) => {
res.json({
env: process.env, // Exposes environment variables!
config: app.settings
});
});
// Default admin credentials
const DEFAULT_ADMIN = {
username: 'admin',
password: 'password123' // Weak default
};
Fixed Code
// Fixed: PHP with secure initialization
<?php
// Explicitly initialize security-critical variables
$authorized = false; // Secure default
// Get input explicitly
$user = filter_input(INPUT_POST, 'user', FILTER_SANITIZE_STRING);
$pass = filter_input(INPUT_POST, 'pass', FILTER_SANITIZE_STRING);
// $authorized cannot be set via POST - it's initialized above
if ($user && $pass && login_user($user, $pass)) {
$authorized = true;
}
if ($authorized) {
generateAdminPage();
}
?>
# Fixed: Python with secure defaults
import os
import secrets
from typing import Optional
class DatabaseConfig:
def __init__(
self,
host: str,
port: int,
username: str,
password: str, # Required - no default
ssl_mode: str = "require" # SSL required by default
):
self.host = host
self.port = port
self.username = username
self.password = password
self.ssl_mode = ssl_mode
# Secure connection defaults
self.max_connections = 100 # Reasonable limit
self.connection_timeout = 30 # 30 second timeout
@classmethod
def from_env(cls):
"""Create config from environment - fails if not configured."""
password = os.environ.get('DB_PASSWORD')
if not password:
raise ValueError("DB_PASSWORD environment variable required")
return cls(
host=os.environ.get('DB_HOST', 'localhost'),
port=int(os.environ.get('DB_PORT', '5432')),
username=os.environ.get('DB_USER', 'app'),
password=password
)
class AppConfig:
def __init__(self):
# Secure defaults
self.debug = False # Debug OFF by default
self.log_level = "WARNING" # Don't log sensitive data
# Strong random session secret
self.session_secret = os.environ.get(
'SESSION_SECRET',
secrets.token_urlsafe(32) # Random if not configured
)
self.session_timeout = 3600 # 1 hour
# Restrictive CORS
self.cors_origins = [] # No origins allowed by default
# Admin disabled by default
self.admin_enabled = False
self.admin_path = f"/admin-{secrets.token_urlsafe(8)}" # Random path
class UserService:
def create_admin_user(self, username: str, password: str = None):
"""Create admin user with provided or generated password."""
if password is None:
# Generate strong random password
password = secrets.token_urlsafe(24)
print(f"Generated admin password: {password}")
print("IMPORTANT: Change this password after first login!")
# Validate password strength
if len(password) < 12:
raise ValueError("Password must be at least 12 characters")
return self._create_user(username, password, role="admin")
def _create_user(self, username: str, password: str, role: str = "user"):
"""Create user with secure defaults."""
return User(
username=username,
password_hash=self._hash_password(password),
role=role,
must_change_password=True, # Force password change
mfa_enabled=False, # But prompt to enable
account_locked=False,
failed_login_attempts=0
)
// Fixed: Java with secure defaults
public class SecurityConfig {
private SecurityConfig() {
// Private constructor - use builder
}
public static class Builder {
private boolean debugMode = false; // Secure default
private String encryptionAlgorithm = "AES";
private int keySize = 256;
private List<String> allowedOrigins = new ArrayList<>(); // Empty by default
private boolean allowCredentials = false;
private int maxRequestsPerMinute = 100; // Reasonable default
private int sessionTimeout = 30 * 60; // 30 minutes
private boolean cookieSecure = true; // HTTPS only
private boolean cookieHttpOnly = true; // Not accessible to JS
public Builder withDebugMode(boolean debug) {
this.debugMode = debug;
return this;
}
public Builder withAllowedOrigins(List<String> origins) {
// Validate no wildcards with credentials
if (allowCredentials && origins.contains("*")) {
throw new IllegalArgumentException(
"Cannot allow credentials with wildcard origin");
}
this.allowedOrigins = new ArrayList<>(origins);
return this;
}
public SecurityConfig build() {
return new SecurityConfig(this);
}
}
}
// Spring Security with secure defaults
@Configuration
@EnableWebSecurity
public class SecureWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// CSRF enabled (default, but explicit)
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// Deny by default, allow specific paths
.and()
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
// Secure headers
.and()
.headers()
.frameOptions().deny()
.contentSecurityPolicy("default-src 'self'")
// Session management
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1);
}
// No default users - must be configured
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Use database or LDAP - no in-memory defaults
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
// Fixed: Node.js/Express with secure defaults
const express = require('express');
const session = require('express-session');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const crypto = require('crypto');
const app = express();
// Require SESSION_SECRET environment variable
if (!process.env.SESSION_SECRET) {
console.error('ERROR: SESSION_SECRET environment variable required');
process.exit(1);
}
// Security headers
app.use(helmet());
// Rate limiting
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // Limit each IP
}));
// Secure session configuration
app.use(session({
secret: process.env.SESSION_SECRET, // From environment
resave: false,
saveUninitialized: false, // Don't create sessions until needed
cookie: {
secure: process.env.NODE_ENV === 'production', // HTTPS in prod
httpOnly: true, // Not accessible to JavaScript
sameSite: 'strict', // CSRF protection
maxAge: 1000 * 60 * 60 // 1 hour
}
}));
// Restrictive CORS - must be explicitly configured
const cors = require('cors');
const allowedOrigins = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(',')
: [];
app.use(cors({
origin: allowedOrigins,
credentials: true
}));
// No debug endpoints in production
if (process.env.NODE_ENV !== 'production') {
app.get('/debug', authRequired, adminRequired, (req, res) => {
// Only show safe debug info
res.json({
uptime: process.uptime(),
memoryUsage: process.memoryUsage()
});
});
}
// No default credentials - must be set up
console.log('Admin account must be created via setup script');
CVE Examples
Many CVEs result from insecure defaults:
- Default credentials: Thousands of CVEs for devices with default admin/admin
- Debug modes: CVEs from debug features enabled by default in production
- Weak crypto defaults: CVEs from weak default encryption settings
Related CWEs
- CWE-344: Use of Invariant Value in Dynamically Changing Context (parent)
- CWE-1419: Incorrect Initialization of Resource (parent)
- CWE-453: Insecure Default Variable Initialization (child)
- CWE-1392: Use of Default Credentials (related)
References
- MITRE Corporation. "CWE-1188: Initialization of a Resource with an Insecure Default." https://cwe.mitre.org/data/definitions/1188.html
- OWASP - Security by Default
- NIST - Secure Configuration Guidelines