T09 · Insecure Skill Coding Practices
- Location
scripts/generate_password.py:4- Finding
Passwords Generated with a Non-Cryptographic Pseudorandom Number Generator
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_password.py, lines 4–24
Vulnerability Type: Use of a cryptographically insecure pseudorandom number generator
Risk Level: HighVulnerable Code
python import random import string import os from datetime import datetime def generate_password(min_length=12, max_length=16, use_uppercase=True, use_lowercase=True, use_digits=True, use_symbols=True): """生成随机长度随机密码""" # 随机选择长度 length = random.randint(min_length, max_length) chars = '' if use_uppercase: chars += string.ascii_uppercase if use_lowercase: chars += string.ascii_lowercase if use_digits: chars += string.digits if use_symbols: chars += string.punctuation if not chars: chars = string.ascii_letters + string.digits password = ''.join(random.choice(chars) for _ in range(length))Technical Analysis
The script uses Python's
randommodule for both password length selection and character selection. This module is based on the deterministic Mersenne Twister algorithm and is not designed for passwords, authentication secrets, session tokens, or other security-sensitive values.If an attacker can infer or recover the generator state—for example, by observing enough outputs, accessing the process state, or correlating outputs with other uses of the same process-wide generator—the attacker may predict subsequent generated passwords. The use of a broad character set does not compensate for a predictable random source.
In addition, selecting every character independently from one combined pool does not guarantee the documented inclusion of at least one uppercase letter, one lowercase letter, one digit, and one symbol.
Attack Path
- A victim invokes the skill to generate a password and uses that password for an account or protected resource.
- An attacker ...[truncated 1053 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace
random.choice()withsecrets.choice(). - Select the length using
secrets.randbelow(max_length - min_length + 1) + min_length. - Build separate enabled character classes and select at least one character from each enabled class.
- Fill the remaining positions using the combined enabled character pool.
- Securely randomize the final character order using a cryptographically secure Fisher–Yates shuffle driven by
secrets.randbelow(). - Validate that
min_lengthcan accommodate the number of required character classes. - Add tests verifying the length bounds and required character-class guarantees.
Example secure design:
python import secrets import string def secure_shuffle(items): for index in range(len(items) - 1, 0, -1): swap_index = secrets.randbelow(index + 1) items[index], items[swap_index] = items[swap_index], items[index] def generate_password(min_length=12, max_length=16): classes = [ string.ascii_uppercase, string.ascii_lowercase, string.digits, string.punctuation, ] if min_length < len(classes) or max_length < min_length: raise ValueError("Invalid password length constraints") length = min_length + secrets.randbelow(max_length - min_length + 1) characters = [secrets.choice(character_class) for character_class in classes] combined = ''.join(classes) characters.extend( secrets.choice(combined) for _ in range(length - len(characters)) ) secure_shuffle(characters) return ''.join(characters), length- Replace
