Back to skill

Security audit

Password Generator

Security checks for vulnerabilities and agentic risk

Overview

This password generator does not appear to steal data, but it automatically saves plaintext passwords and uses weak randomness, so it should be reviewed before use.

Install only if you are comfortable with every generated password being printed and appended in plaintext under the OpenClaw workspace memory directory. Prefer a version that uses cryptographic randomness and does not save passwords unless you explicitly opt in, ideally using a real password manager or encrypted secret store.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_password.py:4
Finding
Passwords Generated with a Non-Cryptographic Pseudorandom Number Generator## Vulnerability Details **File Location**: `scripts/generate_password.py`, lines 4–24 **Vulnerability Type**: Use of a cryptographically insecure pseudorandom number generator **Risk Level**: High ### Vulnerable 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 `random` module 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 1. A victim invokes the skill to generate a password and uses that password for an account or protected resource. 2. An attacker ...[truncated 1053 chars]
Remediation
## Remediation Suggestions - Replace `random.choice()` with `secrets.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_length` can 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 ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_password.py:34
Finding
Generated Passwords Are Persisted in Plaintext Without Enforced Access Controls## Vulnerability Details **File Location**: `scripts/generate_password.py`, lines 34–56 **Vulnerability Type**: Plaintext storage of sensitive credentials with implicit filesystem permissions **Risk Level**: Medium ### Vulnerable Code ```python # 保存到文件 memory_dir = '/root/.openclaw/workspace/memory' os.makedirs(memory_dir, exist_ok=True) password_file = os.path.join(memory_dir, 'passwords.md') date = datetime.now().strftime('%Y-%m-%d') # 添加新密码 new_entry = f""" ## {date} - **随机密码** - 密码: `{password}` - 长度: {length} 位 (12-16位随机) - 字符: 大小写字母 + 数字 + 符号 """ with open(password_file, 'a') as f: f.write(new_entry) print(f"\n密码已保存到: {password_file}") return password, length ``` ### Technical Analysis Every generated password is appended in plaintext to `/root/.openclaw/workspace/memory/passwords.md`. The script does not request explicit per-use consent, provide a non-persistent default, encrypt the stored credentials, enforce retention limits, or explicitly set owner-only permissions. The effective permissions of the directory and file depend on the existing filesystem state and process umask. Therefore, this finding does not establish that the file is universally readable on every installation. However, the code itself does not guarantee that only the intended user can read it. Storing credentials in an agent memory directory also increases exposure to workspace readers, backup systems, indexing processes, later agent operations, and accidental disclosure. The behavior is documented in `SKILL.md`, so it is not hidden. Nevertheless, documenting plaintext credential retention does not remove the confidentiality risk. ### Attack Path 1. A user invokes the skill one or more times, causing generated passwords to accumulate in `passwords.md`. 2. The user applies one or more generated passwords to accounts or protected resources ...[truncated 1096 chars]
Remediation
## Remediation Suggestions - Do not persist generated passwords by default. - Return the password only to the requesting user and require explicit opt-in before writing it to disk. - Prefer integration with a trusted password manager rather than an agent memory file. - If local storage is unavoidable, create the directory with mode `0700` and the file with mode `0600`; verify permissions even when they already exist. - Use an atomic, no-follow file creation strategy to reduce symlink and race-condition risks. - Encrypt retained credentials using a key that is not stored beside the encrypted data. - Add retention controls so stale credentials are deleted rather than accumulated indefinitely. - Avoid printing secrets to logs or interfaces that may retain command output. - Clearly disclose the destination, retention behavior, and security properties before storage. For owner-only file creation, use an explicit descriptor rather than relying solely on the process umask: ```python flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(password_file, flags, 0o600) os.chmod(password_file, 0o600) with os.fdopen(fd, "a", encoding="utf-8") as password_output: password_output.write(new_entry) ``` This permission hardening reduces local exposure but does not address the broader risk of retaining plaintext credentials. Avoiding persistence or using a dedicated encrypted password manager remains preferable.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared purpose is password generation, but the actual behavior also persistently stores the generated password in a local file under memory. This is dangerous because it silently converts a secret-generation function into secret retention, creating credential exposure risk if memory files are later read, indexed, synced, or leaked.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill lacks a clear warning that generated passwords are automatically written to a memory file. Because passwords are highly sensitive secrets, undisclosed persistence materially increases the risk of credential compromise through later access to memory artifacts.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The skill persistently writes newly generated passwords to /root/.openclaw/workspace/memory/passwords.md even though its stated purpose is only to generate passwords. Storing secrets on disk unnecessarily expands exposure to later compromise, accidental disclosure, backup leakage, or access by other tools/users on the system.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
Persistent storage of generated passwords is unjustified for a password-generation utility and directly contradicts the principle of minimizing secret exposure. A generated password should be ephemeral unless the user explicitly requests secure storage, because plaintext archival creates a durable target for attackers.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill performs file-write behavior by instructing execution of a script and saving generated passwords to a local memory file, but it does not declare any tool scope or permissions. This weakens reviewability and containment, and can allow password material to be persisted without explicit authorization boundaries.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger phrases are broad and map to very common user requests such as generating or creating a password, without clarifying that invocation will also write the password to persistent memory. Broad activation increases the chance the skill runs in contexts where the user only expected ephemeral output, causing unintended secret storage.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The manifest description and all user-facing instructions are written only in Chinese, including the trigger phrases the skill expects. There is no indication that the skill is intentionally limited to a Chinese-speaking or region-specific context, and no user opt-in or language choice is offered.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script only informs the user after saving the password, which means the user is not given meaningful prior notice or consent before a sensitive secret is persisted. This increases the chance that users will unknowingly leave credentials in plaintext on disk.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
Natural-language strings and docstrings throughout the script are entirely in Chinese, including user-facing output, with no indication that language selection is configurable or intentionally region-scoped. Under the policy, forcing a specific language without user opt-in can be a locale-policy violation.

Static analysis

No suspicious patterns detected.