weak-password-hashing-anti-pattern

weak-password-hashing-anti-pattern

Security anti-pattern for weak password hashing (CWE-327, CWE-759). Use when generating or reviewing code that stores or verifies user passwords. Detects use of MD5, SHA1, SHA256 without salt, or missing password hashing entirely. Recommends bcrypt, Argon2, or scrypt.

2Sterne
1Forks
Aktualisiert 1/22/2026
SKILL.md
readonlyread-only
name
"weak-password-hashing-anti-pattern"
description

"Security anti-pattern for weak password hashing (CWE-327, CWE-759). Use when generating or reviewing code that stores or verifies user passwords. Detects use of MD5, SHA1, SHA256 without salt, or missing password hashing entirely. Recommends bcrypt, Argon2, or scrypt."

Weak Password Hashing Anti-Pattern

Severity: High

Summary

Weak password hashing is a critical vulnerability that occurs when applications use cryptographic algorithms that are unsuitable for storing passwords. This anti-pattern often involves using fast, general-purpose hash functions (like MD5, SHA-1, or plain SHA-256) without proper salting, or by not hashing passwords at all. Attackers can exploit this to rapidly crack user passwords using pre-computed tables (rainbow tables) or brute-force attacks, especially with modern GPUs. This can lead to mass account compromise and credential stuffing across different services.

The Anti-Pattern

The anti-pattern is using cryptographic hash functions that are too fast or lack essential features like salting and adjustable work factors, making them vulnerable to offline attacks.

BAD Code Example

# VULNERABLE: Using MD5 for password hashing.
import hashlib

def hash_password_md5(password):
    # MD5 is a cryptographically broken hash function.
    # It is extremely fast, and rainbow tables for MD5 are widely available.
    return hashlib.md5(password.encode()).hexdigest()

def verify_password_md5(password, stored_hash):
    return hash_password_md5(password) == stored_hash

# Another example: plain SHA-256 without salting.
def hash_password_sha256_unsalted(password):
    # SHA-256 is a strong hash for data integrity, but too fast for passwords.
    # Without a salt, identical passwords result in identical hashes.
    return hashlib.sha256(password.encode()).hexdigest()

# Problems:
# - Speed: MD5/SHA-256 can compute billions of hashes per second.
# - No Salt: Allows rainbow table attacks and reveals users with identical passwords.
# - No Work Factor: Cannot be slowed down to resist brute-force attacks.

GOOD Code Example

# SECURE: Use a password-hashing algorithm designed to be slow and include a unique salt.
import bcrypt # Or Argon2, scrypt

def hash_password_secure(password):
    # bcrypt automatically generates a unique salt for each password.
    # The `gensalt()` function also allows specifying the work factor (rounds).
    # A higher work factor makes hashing slower, increasing resistance to brute-force attacks.
    hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
    return hashed_password.decode('utf-8') # Store the hashed password as a string.

def verify_password_secure(password, stored_hash):
    # `checkpw()` safely verifies the password against the stored hash.
    # It extracts the salt and work factor from the stored hash and performs a
    # constant-time comparison to prevent timing attacks.
    return bcrypt.checkpw(password.encode('utf-8'), stored_hash.encode('utf-8'))

# Recommended algorithms (in order of current preference):
# 1. Argon2id (best practice for new applications)
# 2. bcrypt
# 3. scrypt

# Always use libraries for password hashing; never implement your own.

Detection

  • Code Review: Search your codebase for password hashing implementations.
    • Look for hashlib.md5(), hashlib.sha1(), or hashlib.sha256() being used for passwords.
    • Check if bcrypt, argon2, or scrypt libraries are used.
    • Verify that a unique, cryptographically secure salt is generated for each password.
  • Database Inspection: Look at the password or password_hash column in your user database.
    • Are the hashes all of the same length and format? (Suggests no salt or static salt).
    • Do they start with prefixes like $2a$ (bcrypt), $argon2id$ (Argon2), or $s2$ (scrypt)?
  • Check for plaintext passwords: Ensure that passwords are never stored in plaintext.

Prevention

  • [ ] Use strong, slow, adaptive password-hashing functions.
    • Argon2id: Currently the recommended algorithm for new applications.
    • bcrypt: A widely used and strong algorithm.
    • scrypt: Another strong algorithm.
  • [ ] Always use a unique, cryptographically secure salt for each password. Modern algorithms like bcrypt and Argon2 handle salt generation automatically.
  • [ ] Adjust the work factor (cost) appropriately. Increase the number of rounds (bcrypt) or memory/time cost (Argon2) until hashing takes about 250-500 milliseconds on your server hardware. This makes brute-forcing expensive for attackers.
  • [ ] Never use fast, general-purpose hash functions like MD5, SHA-1, or plain SHA-256 for passwords. These are designed for speed, not for password storage.
  • [ ] Never store plaintext passwords.

Related Security Patterns & Anti-Patterns

References

You Might Also Like

Related Skills

coding-agent

coding-agent

179Kdev-codegen

Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.

openclaw avataropenclaw
Holen
add-uint-support

add-uint-support

97Kdev-codegen

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

pytorch avatarpytorch
Holen
at-dispatch-v2

at-dispatch-v2

97Kdev-codegen

Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.

pytorch avatarpytorch
Holen
skill-writer

skill-writer

97Kdev-codegen

Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.

pytorch avatarpytorch
Holen

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

oven-sh avataroven-sh
Holen

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

oven-sh avataroven-sh
Holen