Use of Default Password
Description
Use of Default Password occurs when a product uses default passwords for potentially critical functionality, making it easier for attackers to bypass authentication across multiple organizations since default password lists are readily available. Products commonly employ default passwords to simplify manufacturing and system installation. However, when administrators fail to change these credentials, attackers can quickly gain unauthorized access using publicly available default password scanning tools and databases.
Risk
Default passwords have severe implications. Mass exploitation using automated scanners. Botnet recruitment (Mirai-style attacks). Complete authentication bypass. Administrative access to critical infrastructure. Network compromise. Data breaches. Regulatory non-compliance. Supply chain attacks through compromised devices. High likelihood as default credentials are publicly documented.
Solution
Prohibit use of default, hard-coded, or other values that do not vary for each installation during requirements phase (high effectiveness). Emphasize default passwords in product documentation and provide change procedures (limited effectiveness). Force administrators to change credentials upon installation during architecture and design phase (high effectiveness). Allow password modification during setup or operation (moderate effectiveness).
Common Consequences
| Impact | Details |
|---|---|
| Authentication | Scope: Authentication Attackers can leverage unchanged default credentials to obtain unauthorized access and assume administrative roles. |
| Access Control | Scope: Access Control Complete bypass of authentication controls leading to system compromise. |
Example Code
Vulnerable Code
# Vulnerable: Products with default passwords
# VULNERABLE: Router/IoT device defaults
DEVICE_DEFAULTS = {
"admin_user": "admin",
"admin_password": "admin", # VULNERABLE: Common default
"enable_password": "cisco", # VULNERABLE: Well-known default
"wifi_password": "password123", # VULNERABLE: Weak default WiFi
"snmp_community": "public" # VULNERABLE: Default SNMP
}
class VulnerableDevice:
def __init__(self):
# VULNERABLE: Initializes with defaults
self.admin_user = DEVICE_DEFAULTS["admin_user"]
self.admin_password = DEVICE_DEFAULTS["admin_password"]
self.password_changed = False
def authenticate(self, username, password):
# VULNERABLE: Accepts default credentials
if username == self.admin_user and password == self.admin_password:
if not self.password_changed:
# VULNERABLE: Only warns, doesn't enforce change
print("Warning: Please change default password")
return True
return False
def change_password(self, new_password):
# VULNERABLE: Optional, not enforced
self.admin_password = new_password
self.password_changed = True
# VULNERABLE: Database with default root password
class VulnerableDatabase:
DEFAULT_ROOT_PASSWORD = "" # VULNERABLE: Empty default!
def connect(self):
return connect(
user="root",
password=self.DEFAULT_ROOT_PASSWORD # VULNERABLE
)
# VULNERABLE: Web application defaults
class VulnerableWebApp:
def __init__(self):
self.users = {
"admin": "admin123", # VULNERABLE: Default admin
"user": "user123", # VULNERABLE: Default user
"guest": "guest" # VULNERABLE: Default guest
}
def first_login(self, username, password):
if username in self.users and self.users[username] == password:
# VULNERABLE: Doesn't force password change
return {"status": "success", "token": generate_token()}
return {"status": "failed"}
# VULNERABLE: Printer/Scanner defaults
PRINTER_DEFAULTS = {
"admin": "admin",
"tech": "tech",
"service": "service" # VULNERABLE: Service accounts with defaults
}
# VULNERABLE: Industrial control system
PLC_CONFIG = {
"username": "Administrator",
"password": "password", # VULNERABLE: Industrial system default
"level2_password": "level2", # VULNERABLE: Engineering access
"factory_reset_code": "1234" # VULNERABLE: Reset code
}
// Vulnerable: Java applications with default passwords
public class VulnerableProduct {
// VULNERABLE: Hard-coded default passwords
private static final String DEFAULT_ADMIN_USER = "admin";
private static final String DEFAULT_ADMIN_PASS = "admin";
// VULNERABLE: Service account defaults
private static final Map<String, String> SERVICE_ACCOUNTS = Map.of(
"backup", "backup123",
"monitor", "monitor123",
"update", "update123"
);
private String adminPassword = DEFAULT_ADMIN_PASS;
public boolean login(String username, String password) {
// VULNERABLE: Accepts default credentials
if (DEFAULT_ADMIN_USER.equals(username) &&
adminPassword.equals(password)) {
return true;
}
// VULNERABLE: Service accounts with defaults
if (SERVICE_ACCOUNTS.containsKey(username) &&
SERVICE_ACCOUNTS.get(username).equals(password)) {
return true;
}
return false;
}
// VULNERABLE: First-run doesn't enforce password change
public void firstRunSetup() {
System.out.println("Welcome! Default credentials:");
System.out.println("Username: admin");
System.out.println("Password: admin");
System.out.println("We recommend changing the password.");
// VULNERABLE: Recommendation only, not enforced
}
}
// VULNERABLE: Embedded device firmware
public class VulnerableFirmware {
// VULNERABLE: Telnet with default password
public static final String TELNET_PASSWORD = "alpine"; // iOS default
// VULNERABLE: Debug backdoor
public static final String DEBUG_PASSWORD = "debug123";
// VULNERABLE: Factory reset password
public static final String FACTORY_RESET = "000000";
public boolean authenticateTelnet(String password) {
// VULNERABLE: Accepts well-known default
return TELNET_PASSWORD.equals(password);
}
}
// Vulnerable: Node.js with default passwords
// VULNERABLE: Application defaults
const defaultCredentials = {
admin: {
username: 'admin',
password: 'admin' // VULNERABLE
},
database: {
username: 'postgres',
password: 'postgres' // VULNERABLE
},
redis: {
password: '' // VULNERABLE: No password
}
};
// VULNERABLE: First-time setup
async function setupApp() {
const adminExists = await checkAdminExists();
if (!adminExists) {
// VULNERABLE: Creates admin with default password
await createUser({
username: defaultCredentials.admin.username,
password: hashPassword(defaultCredentials.admin.password),
role: 'admin',
mustChangePassword: false // VULNERABLE: Not enforced
});
console.log('Admin account created with default credentials');
console.log('Username: admin, Password: admin');
// VULNERABLE: Attacker reads logs, knows credentials
}
}
// VULNERABLE: Docker/container defaults
const containerDefaults = {
mysql_root_password: 'root',
postgres_password: 'postgres',
mongodb_admin: 'admin',
redis_password: ''
};
// VULNERABLE: IoT device registration
function registerDevice(serialNumber) {
return {
deviceId: serialNumber,
username: 'device',
password: serialNumber.slice(-6), // VULNERABLE: Derived from public info
apiKey: `key_${serialNumber}`
};
}
Fixed Code
# Fixed: Proper password management
import secrets
import string
import os
import sys
class SecureDevice:
def __init__(self):
# FIXED: No default passwords
self.admin_user = None
self.admin_password_hash = None
self.is_setup_complete = False
def initialize(self):
"""FIXED: Force setup before use."""
if not self._check_configuration():
self._run_initial_setup()
def _check_configuration(self):
"""FIXED: Verify credentials are configured and not defaults."""
password_hash = os.environ.get('ADMIN_PASSWORD_HASH')
if not password_hash:
return False
# FIXED: Stored hash of the password, not plaintext
self.admin_password_hash = password_hash
self.admin_user = os.environ.get('ADMIN_USER', 'admin')
self.is_setup_complete = True
return True
def _run_initial_setup(self):
"""FIXED: Interactive setup with strong password requirement."""
print("=== Initial Device Setup ===")
print("A strong password is required.")
# FIXED: Generate and suggest strong password
suggested = self._generate_strong_password()
print(f"\nSuggested password: {suggested}")
password = input("\nEnter admin password (min 12 chars): ").strip()
# FIXED: Validate password strength
if not self._is_strong_password(password):
print("ERROR: Password does not meet requirements:")
print(" - Minimum 12 characters")
print(" - At least one uppercase letter")
print(" - At least one lowercase letter")
print(" - At least one number")
print(" - At least one special character")
sys.exit(1)
# FIXED: Store securely (hash, not plaintext)
password_hash = self._hash_password(password)
print(f"\nSet environment variable:")
print(f"export ADMIN_PASSWORD_HASH='{password_hash}'")
sys.exit(0)
@staticmethod
def _generate_strong_password(length=16):
"""FIXED: Generate cryptographically secure password."""
chars = string.ascii_letters + string.digits + "!@#$%^&*"
return ''.join(secrets.choice(chars) for _ in range(length))
@staticmethod
def _is_strong_password(password):
"""FIXED: Enforce strong password requirements."""
if len(password) < 12:
return False
if not any(c.isupper() for c in password):
return False
if not any(c.islower() for c in password):
return False
if not any(c.isdigit() for c in password):
return False
if not any(c in "!@#$%^&*" for c in password):
return False
return True
def authenticate(self, username, password):
"""FIXED: Authenticate against configured credentials."""
if not self.is_setup_complete:
raise SecurityError("Device not configured")
if username != self.admin_user:
return False
return self._verify_password(password, self.admin_password_hash)
# FIXED: Factory provisioning with unique credentials
class SecureFactoryProvisioning:
def provision_device(self, serial_number):
"""FIXED: Generate unique credentials per device."""
# FIXED: Random credentials, not derived from serial
device_password = secrets.token_urlsafe(16)
api_key = secrets.token_urlsafe(32)
# FIXED: Store in secure provisioning database
self._store_credentials(serial_number, device_password, api_key)
# FIXED: Print on device label during manufacturing
return {
"serial": serial_number,
"initial_password": device_password, # Printed on label
"api_key": api_key
}
def first_boot(self, serial_number):
"""FIXED: Force password change on first boot."""
creds = self._get_provisioned_credentials(serial_number)
if not creds.get('password_changed'):
raise SetupRequired(
"Initial password change required. "
"See device label for initial credentials."
)
// Fixed: Java application without default passwords
public class SecureProduct {
private boolean setupComplete = false;
private String adminPasswordHash;
// FIXED: No default passwords in code
public void initialize() throws SecurityException {
// FIXED: Check for proper configuration
String passwordHash = System.getenv("ADMIN_PASSWORD_HASH");
if (passwordHash == null || passwordHash.isEmpty()) {
throw new SecurityException(
"Admin password not configured. Run setup first."
);
}
// FIXED: Validate hash format (not a weak/default value)
if (passwordHash.length() < 60) { // bcrypt hash is 60 chars
throw new SecurityException(
"Invalid password hash format. Please reconfigure."
);
}
this.adminPasswordHash = passwordHash;
this.setupComplete = true;
}
// FIXED: First-run forces password setup
public static void firstRunSetup() {
Console console = System.console();
if (console == null) {
System.err.println("Console not available for setup");
System.exit(1);
}
System.out.println("=== Initial Setup ===\n");
// FIXED: Generate strong suggested password
String suggested = generateStrongPassword();
System.out.println("Suggested password: " + suggested);
char[] passwordChars = console.readPassword(
"Enter admin password (min 12 chars): "
);
String password = new String(passwordChars);
// FIXED: Validate strength
if (!isStrongPassword(password)) {
System.err.println("Password too weak. Requirements:");
System.err.println("- 12+ characters");
System.err.println("- Mixed case, numbers, symbols");
System.exit(1);
}
// FIXED: Generate hash for storage
String hash = BCrypt.hashpw(password, BCrypt.gensalt(12));
System.out.println("\nSet environment variable:");
System.out.println("export ADMIN_PASSWORD_HASH='" + hash + "'");
// Clear password from memory
Arrays.fill(passwordChars, ' ');
}
private static String generateStrongPassword() {
SecureRandom random = new SecureRandom();
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
sb.append(chars.charAt(random.nextInt(chars.length())));
}
return sb.toString();
}
private static boolean isStrongPassword(String password) {
if (password.length() < 12) return false;
if (!password.chars().anyMatch(Character::isUpperCase)) return false;
if (!password.chars().anyMatch(Character::isLowerCase)) return false;
if (!password.chars().anyMatch(Character::isDigit)) return false;
return password.chars().anyMatch(c -> "!@#$%^&*".indexOf(c) >= 0);
}
}
// Fixed: Node.js without default passwords
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const readline = require('readline');
// FIXED: No default passwords
class SecureApplication {
constructor() {
this.setupComplete = false;
this.adminPasswordHash = null;
}
async initialize() {
// FIXED: Check for configuration
const passwordHash = process.env.ADMIN_PASSWORD_HASH;
if (!passwordHash) {
console.error('ERROR: ADMIN_PASSWORD_HASH not configured');
console.error('Run with --setup flag for initial configuration');
process.exit(1);
}
// FIXED: Validate hash format
if (!passwordHash.startsWith('$2')) { // bcrypt prefix
console.error('ERROR: Invalid password hash format');
process.exit(1);
}
this.adminPasswordHash = passwordHash;
this.setupComplete = true;
}
static async runSetup() {
console.log('=== Initial Setup ===\n');
// FIXED: Generate strong suggested password
const suggested = crypto.randomBytes(12).toString('base64');
console.log(`Suggested password: ${suggested}`);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const password = await new Promise(resolve => {
rl.question('Enter admin password (min 12 chars): ', resolve);
});
rl.close();
// FIXED: Validate strength
if (!SecureApplication.isStrongPassword(password)) {
console.error('\nPassword too weak. Requirements:');
console.error('- 12+ characters');
console.error('- Mixed case, numbers, symbols');
process.exit(1);
}
// FIXED: Generate hash
const hash = await bcrypt.hash(password, 12);
console.log('\nSet environment variable:');
console.log(`export ADMIN_PASSWORD_HASH='${hash}'`);
process.exit(0);
}
static isStrongPassword(password) {
if (password.length < 12) return false;
if (!/[A-Z]/.test(password)) return false;
if (!/[a-z]/.test(password)) return false;
if (!/[0-9]/.test(password)) return false;
if (!/[!@#$%^&*]/.test(password)) return false;
return true;
}
}
// FIXED: CLI handling
if (process.argv.includes('--setup')) {
SecureApplication.runSetup();
} else {
const app = new SecureApplication();
app.initialize();
}
CVE Examples
- CVE-2016-1560: DVR devices with default credentials exploited by Mirai botnet.
- CVE-2020-9054: ZyXEL devices with default admin:1234 credentials.
- CVE-2021-36260: Hikvision cameras with default passwords.
Related CWEs
- CWE-1392: Use of Default Credentials (parent)
- CWE-798: Use of Hard-coded Credentials (related)
- CWE-259: Use of Hard-coded Password (related)
References
- MITRE Corporation. "CWE-1393: Use of Default Password." https://cwe.mitre.org/data/definitions/1393.html
- CISA. "Default Passwords in Critical Infrastructure"
- OWASP. "Default Passwords"