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

ImpactDetails
AuthenticationScope: Authentication

Attackers can gain privileges or assume identity using unchanged default credentials.
Access ControlScope: 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.

  • 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

  1. MITRE Corporation. "CWE-1392: Use of Default Credentials." https://cwe.mitre.org/data/definitions/1392.html
  2. CISA. "Default Passwords and Best Practices"
  3. OWASP IoT. "Default Credentials"