This weakness occurs when software relies on credentials—passwords, API keys, encryption keys, or tokens—that are too simple, short, or predictable to resist…
This weakness occurs when software relies on credentials—passwords, API keys, encryption keys, or tokens—that are too simple, short, or predictable to resist guessing or brute-force attacks. An attacker with access to a login interface or credential store can compromise accounts or systems in a reasonable timeframe, often without triggering rate-limiting or account lockouts.
02How It Happens
Weak credentials arise from several common patterns: hardcoded default passwords that are never changed, user-chosen passwords that lack complexity requirements, cryptographic keys generated with insufficient entropy, or credentials stored in plaintext or with weak hashing. Systems that do not enforce minimum password length, character diversity, or expiration policies, or that lack rate-limiting on login attempts, make brute-force attacks practical. Even strong credential policies fail if the underlying storage mechanism (database, configuration file, or key management system) is compromised and the credentials are not properly hashed or encrypted.
03Real-World Impact
Compromised credentials grant attackers direct access to user accounts, administrative panels, or backend systems. This can lead to unauthorized data access, account takeover, privilege escalation, lateral movement within a network, or complete system compromise. In multi-tenant environments, a single weak credential can expose all users' data. The impact is often severe because credentials are the first line of defense; once bypassed, other security controls may be irrelevant.
04Vulnerable & Fixed Patterns
Vulnerable pattern
import sqlite3
def authenticate_user(username, password):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# Passwords stored as plaintext; no complexity enforcement
cursor.execute(
"SELECT * FROM users WHERE username = ? AND password = ?",
(username, password)
)
user = cursor.fetchone()
conn.close()
return user is not None
Why it's vulnerable: Passwords are stored in plaintext and there is no enforcement of password complexity, length, or uniqueness. An attacker who gains database access reads all passwords directly; even without database access, simple passwords can be guessed quickly.
Fixed pattern
import sqlite3
import hashlib
import secrets
def authenticate_user(username, password):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute("SELECT password_hash, salt FROM users WHERE username = ?", (username,))
row = cursor.fetchone()
conn.close()
if row is None:
return False
stored_hash, salt = row
# Use PBKDF2 or bcrypt; here shown with hashlib for illustration
computed_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
return computed_hash == stored_hash
def set_password(username, password):
# Enforce minimum length and complexity
if len(password) < 12 or not any(c.isupper() for c in password):
raise ValueError("Password must be at least 12 chars with uppercase letters")
salt = secrets.token_bytes(32)
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
# Store hash and salt, never plaintext
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute("UPDATE users SET password_hash = ?, salt = ? WHERE username = ?",
(password_hash, salt, username))
conn.commit()
conn.close()
Vulnerable pattern
<?php
// Credentials hardcoded and weak
define('DB_USER', 'admin');
define('DB_PASS', '123456');
// No password complexity enforcement
function register_user($username, $password) {
global $wpdb;
// Password stored as-is, no hashing
$wpdb->insert('users', array(
'username' => $username,
'password' => $password
));
}
?>
Why it's vulnerable: Hardcoded credentials are trivial to guess; user passwords are stored unhashed and in plaintext. Anyone with database access or who intercepts traffic sees all credentials immediately.
Fixed pattern
<?php
// Credentials loaded from environment, not hardcoded
define('DB_USER', getenv('DB_USER'));
define('DB_PASS', getenv('DB_PASS'));
// Enforce password policy and use proper hashing
function register_user($username, $password) {
global $wpdb;
// Enforce minimum complexity
if (strlen($password) < 12 || !preg_match('/[A-Z]/', $password)) {
wp_die('Password must be at least 12 characters with uppercase letters');
}
// Use bcrypt via wp_hash_password or password_hash
$password_hash = wp_hash_password($password);
$wpdb->insert('users', array(
'username' => sanitize_user($username),
'password' => $password_hash
));
}
// Verify with wp_check_password or password_verify
function authenticate_user($username, $password) {
global $wpdb;
$user = $wpdb->get_row($wpdb->prepare(
"SELECT password FROM users WHERE username = %s",
$username
));
return $user && wp_check_password($password, $user->password);
}
?>
05Prevention Checklist
Enforce password policies: Require minimum length (12+ characters), uppercase, lowercase, numbers, and symbols. Reject common dictionary words and previously breached passwords.
Use strong hashing: Store passwords with bcrypt, scrypt, or Argon2—never plaintext or weak algorithms like MD5/SHA1. Use a unique salt per password.
Never hardcode credentials: Load database passwords, API keys, and secrets from environment variables or secure vaults, never from source code or configuration files.
Implement rate-limiting and account lockout: Limit login attempts per IP and per account to slow brute-force attacks; add CAPTCHA after repeated failures.
Rotate credentials regularly: Enforce password expiration policies and require periodic updates for service accounts and API keys.
Audit credential storage: Regularly review where credentials are stored (databases, logs, backups, caches) and ensure they are encrypted or hashed.
06Signs You May Already Be Affected
Check for unexpected login activity in access logs, particularly repeated failed attempts from a single IP or successful logins from unusual locations or times. Review user account creation dates and permissions for accounts you do not recognize. If you discover plaintext passwords in database backups, configuration files, or application logs, your system has been storing credentials insecurely and may already be compromised.