Use of Default Credentials
Description
Use of Default Credentials occurs when a product implements default credentials (passwords or cryptographic keys) for potentially critical functionality, creating authentication bypass risks. Products often employ default keys and passwords to streamline manufacturing and system administration. However, when administrators fail to modify these defaults, attackers can quickly circumvent authentication across multiple organizations. Default credential lists are widely available, making exploitation trivial.
Risk
Default credentials have severe implications. Mass exploitation across all unpatched installations. Botnet recruitment of IoT devices. Complete authentication bypass. Administrative access to critical systems. Lateral movement in networks. Data breaches. Supply chain attacks. Regulatory compliance violations. High likelihood as default credential lists are publicly available.
Solution
Prohibit use of default, hard-coded, or other values that do not vary for each installation during requirements phase (high effectiveness). Force the administrator to change the credential upon installation during architecture and design phase (high effectiveness). Product administrators may modify defaults during setup or operation (moderate effectiveness). Generate unique credentials per device during manufacturing.
Common Consequences
| Impact | Details |
|---|---|
| Authentication | Scope: Authentication Attackers can gain privileges or assume identity using unchanged default credentials. |
| Access Control | Scope: Access Control Complete bypass of authentication controls through known default credentials. |
Example Code
Vulnerable Code
# Vulnerable: Default credentials in application
# VULNERABLE: Default credentials defined in code
DEFAULT_ADMIN_USER = "admin"
DEFAULT_ADMIN_PASSWORD = "admin"
DEFAULT_API_KEY = "demo_key_12345"
class VulnerableApplication:
def __init__(self):
# VULNERABLE: Using defaults without forcing change
self.admin_username = DEFAULT_ADMIN_USER
self.admin_password = DEFAULT_ADMIN_PASSWORD
self.api_key = DEFAULT_API_KEY
self.is_default_password = True # Flag exists but not enforced
def authenticate(self, username, password):
# VULNERABLE: Allows login with default credentials
if username == self.admin_username and password == self.admin_password:
return True
return False
def verify_api_key(self, key):
# VULNERABLE: Accepts default API key
return key == self.api_key
# VULNERABLE: Database with default credentials
DATABASE_CONFIG = {
"host": "localhost",
"port": 5432,
"database": "production_db",
"user": "postgres", # VULNERABLE: Default PostgreSQL user
"password": "postgres" # VULNERABLE: Default password
}
# VULNERABLE: IoT device configuration
IOT_DEVICE_CONFIG = {
"ssh_user": "root",
"ssh_password": "root", # VULNERABLE: Common default
"web_admin": "admin",
"web_password": "admin", # VULNERABLE: Default web password
"telnet_enabled": True, # VULNERABLE: Telnet with defaults
"firmware_update_key": "update123" # VULNERABLE: Default update key
}
# VULNERABLE: Router default configuration
ROUTER_CONFIG = {
"admin_user": "admin",
"admin_pass": "password", # VULNERABLE: Common router default
"wifi_password": "12345678", # VULNERABLE: Weak default WiFi
"wps_pin": "12345670" # VULNERABLE: Default WPS PIN
}
// Vulnerable: Java application with default credentials
public class VulnerableSystem {
// VULNERABLE: Hard-coded default credentials
private static final String DEFAULT_ADMIN = "administrator";
private static final String DEFAULT_PASSWORD = "changeme";
private static final String DEFAULT_SECRET_KEY = "default_secret_key_123";
private String adminPassword = DEFAULT_PASSWORD;
private boolean passwordChanged = false;
// VULNERABLE: No forced password change
public boolean authenticate(String username, String password) {
if (username.equals(DEFAULT_ADMIN) && password.equals(adminPassword)) {
// VULNERABLE: Warns but allows access with default
if (!passwordChanged) {
System.out.println("Warning: Using default password");
}
return true;
}
return false;
}
// VULNERABLE: Optional password change
public void changePassword(String newPassword) {
// VULNERABLE: User can skip this step
this.adminPassword = newPassword;
this.passwordChanged = true;
}
// VULNERABLE: Default JWT secret
public String generateToken(String userId) {
// VULNERABLE: Uses default secret if not configured
String secret = System.getenv("JWT_SECRET");
if (secret == null) {
secret = DEFAULT_SECRET_KEY; // VULNERABLE: Falls back to default
}
return createJWT(userId, secret);
}
}
// VULNERABLE: Database connection with defaults
public class VulnerableDatabase {
public Connection getConnection() throws SQLException {
String host = getProperty("db.host", "localhost");
String user = getProperty("db.user", "sa"); // VULNERABLE: Default SA
String pass = getProperty("db.pass", ""); // VULNERABLE: Empty password
return DriverManager.getConnection(
"jdbc:sqlserver://" + host,
user,
pass
);
}
}
// Vulnerable: Node.js with default credentials
// VULNERABLE: Default configuration
const defaultConfig = {
admin: {
username: 'admin',
password: 'admin123' // VULNERABLE: Default admin password
},
database: {
user: 'root',
password: 'root' // VULNERABLE: Default DB password
},
jwt: {
secret: 'your-secret-key' // VULNERABLE: Placeholder secret
},
encryption: {
key: '0123456789abcdef' // VULNERABLE: Default encryption key
}
};
// VULNERABLE: Uses defaults without validation
function getConfig() {
return {
admin: {
username: process.env.ADMIN_USER || defaultConfig.admin.username,
password: process.env.ADMIN_PASS || defaultConfig.admin.password
},
// Falls back to insecure defaults
};
}
// VULNERABLE: First-time setup doesn't force password change
async function setupApplication() {
const config = getConfig();
// VULNERABLE: Just logs warning, doesn't block
if (config.admin.password === defaultConfig.admin.password) {
console.warn('Warning: Using default admin password');
// Should force password change here!
}
await startServer(config);
}
// VULNERABLE: API key generation with default fallback
function getApiKey() {
return process.env.API_KEY || 'default_api_key_for_development';
}
Fixed Code
# Fixed: Proper handling of credentials
import secrets
import os
import sys
class SecureApplication:
def __init__(self):
# FIXED: No default credentials
self.admin_username = None
self.admin_password = None
self.api_key = None
self.is_initialized = False
def initialize(self):
"""FIXED: Force credential setup before use."""
if not self._credentials_configured():
raise SecurityError(
"Application cannot start without configured credentials. "
"Run setup wizard to configure admin credentials."
)
self.is_initialized = True
def _credentials_configured(self):
"""FIXED: Check if non-default credentials are set."""
# Check environment or secure storage
username = os.environ.get('ADMIN_USERNAME')
password = os.environ.get('ADMIN_PASSWORD')
api_key = os.environ.get('API_KEY')
if not all([username, password, api_key]):
return False
# FIXED: Reject known default values
default_values = ['admin', 'password', 'changeme', 'default', '123456']
if password.lower() in default_values:
return False
self.admin_username = username
self.admin_password = password
self.api_key = api_key
return True
@staticmethod
def setup_wizard():
"""FIXED: Interactive setup for first-time configuration."""
print("=== First-Time Setup ===")
username = input("Enter admin username: ").strip()
# FIXED: Generate strong default, require confirmation
suggested_password = secrets.token_urlsafe(16)
print(f"Suggested password: {suggested_password}")
password = input("Enter admin password (or press Enter for suggested): ").strip()
if not password:
password = suggested_password
# FIXED: Validate password strength
if not SecureApplication._is_strong_password(password):
print("Error: Password too weak. Must be 12+ chars with mixed case, digits, symbols.")
sys.exit(1)
# FIXED: Generate unique API key
api_key = secrets.token_urlsafe(32)
print("\nAdd these to your environment:")
print(f"export ADMIN_USERNAME='{username}'")
print(f"export ADMIN_PASSWORD='{password}'")
print(f"export API_KEY='{api_key}'")
return username, password, api_key
@staticmethod
def _is_strong_password(password):
"""FIXED: Validate password strength."""
if len(password) < 12:
return False
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)
has_digit = any(c.isdigit() for c in password)
return has_upper and has_lower and has_digit
# FIXED: Database configuration without defaults
def get_database_config():
"""FIXED: Require explicit database credentials."""
required_vars = ['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASSWORD']
config = {}
missing = []
for var in required_vars:
value = os.environ.get(var)
if not value:
missing.append(var)
else:
config[var.lower().replace('db_', '')] = value
if missing:
raise EnvironmentError(
f"Missing required database configuration: {', '.join(missing)}"
)
# FIXED: Reject obvious defaults
if config['password'] in ['', 'postgres', 'root', 'password']:
raise SecurityError("Database password appears to be a default value")
return config
// Fixed: Java application without default credentials
public class SecureSystem {
// FIXED: No default credentials in code
private String adminPassword;
private boolean initialized = false;
public void initialize() throws SecurityException {
// FIXED: Require credential configuration
String password = System.getenv("ADMIN_PASSWORD");
if (password == null || password.isEmpty()) {
throw new SecurityException(
"ADMIN_PASSWORD environment variable must be set"
);
}
// FIXED: Reject default/weak values
if (isDefaultOrWeakPassword(password)) {
throw new SecurityException(
"Password appears to be a default or weak value. " +
"Please set a strong, unique password."
);
}
this.adminPassword = password;
this.initialized = true;
}
private boolean isDefaultOrWeakPassword(String password) {
String[] defaults = {
"admin", "password", "changeme", "default",
"root", "123456", "administrator"
};
String lower = password.toLowerCase();
for (String def : defaults) {
if (lower.equals(def) || lower.contains(def)) {
return true;
}
}
// FIXED: Check length
return password.length() < 12;
}
public boolean authenticate(String username, String password) {
// FIXED: Require initialization
if (!initialized) {
throw new IllegalStateException("System not initialized");
}
// Verify credentials...
return verifyPassword(password, adminPassword);
}
// FIXED: First-run setup enforcement
public static void main(String[] args) {
SecureSystem system = new SecureSystem();
try {
system.initialize();
} catch (SecurityException e) {
System.err.println("ERROR: " + e.getMessage());
System.err.println("\nPlease configure credentials:");
System.err.println(" export ADMIN_PASSWORD='<strong-password>'");
System.exit(1);
}
// Continue with initialized system
}
}
// FIXED: Secure JWT secret handling
public class SecureJWT {
private final String secret;
public SecureJWT() {
this.secret = loadSecret();
}
private String loadSecret() {
String secret = System.getenv("JWT_SECRET");
// FIXED: No fallback to default
if (secret == null || secret.isEmpty()) {
throw new SecurityException(
"JWT_SECRET must be configured"
);
}
// FIXED: Validate secret strength
if (secret.length() < 32) {
throw new SecurityException(
"JWT_SECRET must be at least 32 characters"
);
}
return secret;
}
}
// Fixed: Node.js without default credentials
const crypto = require('crypto');
// FIXED: No default credentials
const requiredEnvVars = [
'ADMIN_USERNAME',
'ADMIN_PASSWORD',
'JWT_SECRET',
'DB_PASSWORD',
'ENCRYPTION_KEY'
];
// FIXED: Validate configuration at startup
function validateConfiguration() {
const missing = [];
const weak = [];
const defaultPatterns = [
'admin', 'password', 'secret', 'changeme',
'default', '123456', 'root', 'your-'
];
for (const varName of requiredEnvVars) {
const value = process.env[varName];
if (!value) {
missing.push(varName);
continue;
}
// FIXED: Check for default/weak values
const lower = value.toLowerCase();
for (const pattern of defaultPatterns) {
if (lower.includes(pattern)) {
weak.push(varName);
break;
}
}
// FIXED: Check minimum length for secrets
if (varName.includes('SECRET') || varName.includes('KEY')) {
if (value.length < 32) {
weak.push(`${varName} (too short)`);
}
}
}
if (missing.length > 0) {
console.error('ERROR: Missing required configuration:');
missing.forEach(v => console.error(` - ${v}`));
process.exit(1);
}
if (weak.length > 0) {
console.error('ERROR: Weak/default values detected:');
weak.forEach(v => console.error(` - ${v}`));
console.error('\nPlease use strong, unique values.');
process.exit(1);
}
return true;
}
// FIXED: Generate secure default for setup
function generateSecureCredentials() {
return {
password: crypto.randomBytes(16).toString('base64'),
jwtSecret: crypto.randomBytes(32).toString('hex'),
encryptionKey: crypto.randomBytes(32).toString('hex')
};
}
// FIXED: First-run setup
async function firstTimeSetup() {
console.log('=== First-Time Setup ===\n');
const credentials = generateSecureCredentials();
console.log('Generated secure credentials:');
console.log('Add these to your environment:\n');
console.log(`export ADMIN_PASSWORD='${credentials.password}'`);
console.log(`export JWT_SECRET='${credentials.jwtSecret}'`);
console.log(`export ENCRYPTION_KEY='${credentials.encryptionKey}'`);
console.log('\nRestart the application after configuration.');
process.exit(0);
}
// FIXED: Startup validation
async function startApplication() {
// Check if first run
const hasConfig = requiredEnvVars.every(v => process.env[v]);
if (!hasConfig) {
await firstTimeSetup();
}
validateConfiguration();
// Continue with validated configuration
console.log('Configuration validated, starting application...');
}
startApplication();
CVE Examples
- CVE-2022-30270: RTU SSH default credentials enabling unauthorized access.
- CVE-2021-41192: Default secret keys allowing authentication bypass.
- CVE-2021-38759: Microcontroller default password enabling device takeover.
- CVE-2016-1560: DVR systems with default credentials exploited by Mirai botnet.
Related CWEs
- CWE-1391: Use of Weak Credentials (parent)
- CWE-1393: Use of Default Password (child)
- CWE-1394: Use of Default Cryptographic Key (child)
- CWE-255: Credentials Management Errors (category)
References
- MITRE Corporation. "CWE-1392: Use of Default Credentials." https://cwe.mitre.org/data/definitions/1392.html
- CISA. "Default Passwords and Best Practices"
- OWASP IoT. "Default Credentials"