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

ImpactDetails
AuthenticationScope: Authentication

Attackers can leverage unchanged default credentials to obtain unauthorized access and assume administrative roles.
Access ControlScope: 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.

  • CWE-1392: Use of Default Credentials (parent)
  • CWE-798: Use of Hard-coded Credentials (related)
  • CWE-259: Use of Hard-coded Password (related)

References

  1. MITRE Corporation. "CWE-1393: Use of Default Password." https://cwe.mitre.org/data/definitions/1393.html
  2. CISA. "Default Passwords in Critical Infrastructure"
  3. OWASP. "Default Passwords"