Back to skill

Security audit

Password Manager

Security checks for vulnerabilities and agentic risk

Overview

This is a local password manager, but it exposes or mishandles secrets in several user-facing paths and has misleading safety-critical documentation.

Review carefully before installing. The skill is local and does not show exfiltration or remote-code behavior, but it handles highly sensitive credentials and currently has unsafe defaults and examples. Avoid putting master passwords or saved secrets in chat, command-line arguments, or long-lived environment variables; do not rely on the documented backup/restore behavior; and treat the vault/cache files as sensitive assets requiring restrictive filesystem permissions.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/password-manager.mjs:238
Finding

Secrets Exposed Through Command-Line Arguments

Content
View full analysis
args[i - 1] === '--name'); const type = args.find((_, i) => args[i - 1] === '--type') || 'password'; const username = args.find((_, i) => args[i - 1] === '--username'); const password = args.find((_, i) => args[i - 1] === '--password'); const tagsArg = args.find((_, i) => args[i - 1] === '--tags'); ``` The master-password change command also accepts both master passwords through arguments: ```javascript async function cmdChangePassword() { const rl = createReadline(); const oldPassword = args.find((_, i) => args[i - 1] === '--old'); const newPassword = args.find((_, i) => args[i - 1] === '--new'); if (!oldPassword || !newPassword) { console.log('❌ Missing --old or --new parameter'); console.log('Usage: password-manager change-password --old --new '); rl.close(); return; } ``` ### Technical Analysis The CLI accepts stored passwords, tokens, and old and new master passwords directly through command-line arguments. Process arguments are not a protected secret-input channel. Depending on the operating system and execution environment, they may be exposed through: - Process inspection utilities and process-monitoring APIs - Shell history - CI/CD job definitions and logs - Terminal session recording - Audit and observability systems - Parent-process telemetry - Error reports that capture complete command lines Exposure of the master password is especially severe because it permits decryption of the entire vault. Exposure of an entry password or token directly compromises that individual credential. ### Attack Path 1. A user follows the docume ...[truncated 1167 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/storage.js:51
Finding

Sensitive Vault Files Created Without Explicit Restrictive Permissions

Content
View full analysis
{ if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } }); } ``` The vault and cache are written without an explicit file mode: ```javascript const packed = crypto.encryptAndPack(key, vaultData, salt); writeFileSync(VAULT_FILE, packed); // Cache key (encrypted version using master password) cacheKey(key, masterPassword); ``` ```javascript const encrypted = crypto.encryptAndPack(cacheEncryptionKey, keyData); writeFileSync(CACHE_FILE, encrypted, 'utf8'); ``` History files and subsequent vault versions are handled in the same way: ```javascript if (existsSync(VAULT_FILE)) { const timestamp = Date.now(); const historyFile = join(DEFAULT_DATA_DIR, `vault.${timestamp}.enc`); // Copy old file to history const oldPacked = readFileSync(VAULT_FILE); writeFileSync(historyFile, oldPacked); vaultData.history = vaultData.history || []; vaultData.history.push({ version: vaultData.history.length + 1, timestamp: new Date().toISOString(), file: historyFile }); } vaultData.updatedAt = new Date().toISOString(); // Convert hex salt back to buffer for consistent encryption const saltBuffer = Buffer.from(vaultData.salt, 'hex'); // Encrypt and save with the original salt const packed = crypto.encryptAndPack(decryptionKey, vaultData, saltBuffer); writeFileSync(VAULT_FILE, packed); ``` ### Technical Analysis Directory and file permissions are inherited from the process umask because the code does not explicitly request restrictive modes. In environments with a permissive umask, another local account or service may be ab ...[truncated 1482 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/crypto.js:13
Finding

Globally Fixed Salt Used for Cache-Key Derivation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
hooks/openclaw/handler.mjs:556
Finding

Sensitive-Information Hook Returns Raw Detected Secrets

Content
View full analysis
= threshold; // Extract value (use capture group if available, otherwise use full match) const value = match[1] || match[0]; results.push({ type, name: rule.name, sensitivity: rule.sensitivity, value, fullMatch: match[0], position: match.index, length: match[0].length, shouldAsk: rule.autoAsk && meetsThreshold, suggestedEntryName: generateEntryName(rule.suggestedEntryName, results.length) }); } ``` The complete detection objects are returned by the user-message hook: ```javascript export async function onUserMessage(message) { const config = storage.loadConfig(); if (!config.autoDetect.enabled) { return {}; } const detections = detector.detect(message.content, config.autoDetect); if (detections.length > 0) { // Log detection events detections.forEach(d => { storage.logDetection(d.type, 'asked', 'pending'); }); return { hasSensitiveInfo: true, detections, prompt: detector.generatePrompt(detections) }; } return {}; } ``` ### Technical Analysis The hook returns `detections` without redaction. Each detection includes both `value` and `fullMatch`, which can contain complete API keys, tokens, passwords, and database connection strings. This conflicts with the documented hook shape in `hooks/openclaw/HOOK.md`, which shows only metadata such as type, name, sensitivity, and suggested entry name. Returning raw secrets expands the number of components that process plaintext credentials. Hook re ...[truncated 1336 chars]
Remediation
View remediation
({ type: d.type, name: d.name, sensitivity: d.sensitivity, position: d.position, length: d.length, suggestedEntryName: d.suggestedEntryName })); ``` 3. Keep raw matched values only in the narrowest possible in-memory scope. 4. Redact secrets from hook exceptions, debugging output, traces, and telemetry. 5. Add automated tests asserting that hook responses never contain known test credentials. 6. Document the exact hook response schema and enforce it at runtime. 7. If saving a detected value is required, use an explicit protected handoff rather than returning the plaintext through general hook output. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/storage.js:132
Finding

Vault Initialization Overwrites an Existing Vault Without Destructive Confirmation

Content
View full analysis
console.log(` - ${e}`)); console.log(''); const force = args.includes('--force'); if (!force) { const continueAnyway = await prompt(rl, 'Continue anyway? (y/N): '); if (continueAnyway.toLowerCase() !== 'y') { console.log('Cancelled'); rl.close(); process.exit(0); } } } const result = storage.initializeVault(password); console.log('✅', result.message); rl.close(); } ``` The storage function writes directly over the current vault: ```javascript export function initializeVault(masterPassword) { ensureDirectories(); const { key, salt } = crypto.deriveKey(masterPassword); const vaultData = { version: 1, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), salt: salt.toString('hex'), entries: [], ...[truncated 2138 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code aligns with part of the description: it does provide local cryptographic primitives using AES-256-GCM and PBKDF2, plus secure random utilities. However, the declared purpose describes a full local password management skill with password generation and sensitive info detection. This code chunk is only a cryptography helper module and does not show vault/storage management, credential CRUD, password generation policy/composition features, or any detection/scanning of sensitive information. Therefore the description overstates the implemented behavior in this supplied chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broader password management skill featuring AES-256-GCM encryption, password generation, and sensitive info detection. However, this code chunk only covers password-related generation and evaluation utilities. It does not implement encryption, decryption, vault/storage behavior, or any scanning/detection of sensitive information. While password generation aligns with part of the description, the actual code materially underdelivers on the stated primary capabilities and adds some unmentioned utility behavior like strength checking and API-key-format generation. Therefore, the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The supplied code is a validator module, not an encryption, password generation, or sensitive-information detection module. It performs schema-like checks on entries, password strength validation, search query validation, and backup path validation. While this behavior is broadly related to a password management skill, the declared description specifically highlights AES-256-GCM encryption, password generation, and sensitive info detection, none of which are implemented in this chunk. Because the actual code’s primary purpose is narrower and materially different from the declared feature set, this is a description-behavior mismatch for this code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 410)May include surrounding context.

md
- **Documentation**: `SKILL.md`, `tests/SECURITY-FIXES.md`

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The non-TTY fallback accepts the master password using visible input without any warning, which can expose the secret directly on-screen, in terminal recordings, logs, or upstream pipeline captures. Because this is the master password for a local password vault, disclosure can lead to full compromise of all stored credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

For markdown files, safety-affecting behaviors should include warnings when they may impact user data or system integrity. This entry notes that the vault is automatically re-encrypted and cache updated during change-password, but does not warn users to back up data, verify the old password carefully, or understand the consequences if the operation fails or is misused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file announces PASSWORD_MANAGER_MASTER_PASSWORD support, which affects handling of sensitive credentials. The entry provides no warning that environment variables may be exposed through shell history, process listings, CI logs, or shared automation environments, so users are not alerted to the privacy and security implications.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
74% confidence
Finding

The skill advertises handling highly sensitive secrets and explicitly documents use of the PASSWORD_MANAGER_MASTER_PASSWORD environment variable, yet the manifest declares no tool scope or permissions boundaries. In a password-manager context, undeclared environment access weakens reviewability and can enable unintended secret exposure or overbroad runtime privileges.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The examples instruct users to place secrets directly on the command line, where they may be exposed through shell history, process listings, terminal logging, and CI job records. In a password-manager skill, normalizing this practice directly undermines the core goal of protecting credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Documenting --show-password without any caution encourages plaintext disclosure of secrets on-screen and into terminal scrollback, screen recordings, logs, and remote session transcripts. Because this skill handles credentials, secret display features require strong friction and explicit warnings.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The examples explicitly teach the agent to ask for and receive the user's master password in chat, which is a poor pattern because chat content may be retained in transcripts, telemetry, memory, or logs outside the vault's encryption boundary. In an agent setting, collecting master secrets through conversational channels significantly increases exposure surface.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Backup and restore are sensitive operations, yet the documentation omits warnings that backups contain highly sensitive encrypted vault material and that restore may overwrite current data. This increases the chance of accidental data loss and insecure backup handling.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 172)May include surrounding context.

md
| `--tags` | Tags (comma-separated, optional) |
| `--length` | Password length (default: 32) |
| `--show-password` | Show password in plaintext |
| `--confirm` | Skip confirmation (for sensitive operations) |
| `--old` | Old master password (for change-password) |
| `--new` | New master password (for change-password) |

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/password-manager.mjs (reported line 755)May include surrounding context.

js
| `--tags` | Tags (comma-separated, optional) |
| `--length` | Password length (default: 32) |
| `--show-password` | Show password in plaintext |
| `--confirm` | Skip confirmation (for sensitive operations) |
| `--old` | Old master password (for change-password) |
| `--new` | New master password (for change-password) |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document recommends storing the master password in an environment variable for automation, but the warning given is too narrow and understates broader leakage channels such as inherited environments, crash dumps, debug logs, CI metadata, container introspection, and multi-user host exposure. For a password manager, weakening master secret handling materially increases compromise risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The FAQ explicitly states that the current version does not support changing the master password and requires reinitialization, which directly contradicts earlier documented commands, tools, and usage examples for change-password. This is an intent-level contradiction in the skill's own documentation that could mislead users about a sensitive security operation.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · hooks/openclaw/HOOK.md (reported line 9)May include surrounding context.

md
| Tool Name | Description |
|-----------|-------------|
| `password_manager_add` | Add entry to password manager |
| `password_manager_get` | Get entry content |
| `password_manager_update` | Update entry |
| `password_manager_delete` | Delete entry (sensitive operation) |

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · hooks/openclaw/handler.mjs (reported line 26)May include surrounding context.

js
| Tool Name | Description |
|-----------|-------------|
| `password_manager_add` | Add entry to password manager |
| `password_manager_get` | Get entry content |
| `password_manager_update` | Update entry |
| `password_manager_delete` | Delete entry (sensitive operation) |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation explicitly shows retrieving an entry with showPassword: true but does not warn that this exposes plaintext secrets to the chat/UI, logs, screenshots, or other downstream consumers. In a password-manager skill, normalizing secret display without a clear warning or safer default increases the risk of accidental credential disclosure even if the underlying feature is intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

password_manager_get defaults showPassword to true, so plaintext secrets are returned unless the caller explicitly opts out. In an LLM agent context, this increases the chance of accidental credential exposure in model outputs, logs, chat history, or downstream tool chains.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The delete tool schema/documentation says deletion requires the user to re-enter the master password, but the implementation only trusts a caller-supplied boolean confirmed. In an agent/tooling environment, another component or prompt-influenced agent can set confirmed: true and trigger irreversible deletion without the stronger step-up authentication the interface promises.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The user message hook automatically scans all message content for sensitive information whenever auto-detect is enabled, but this file shows no explicit disclosure or consent gate. Even if intended for protection, automatic inspection of arbitrary user content can create privacy, trust, and data-handling risks, especially if detections are logged via storage.logDetection.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Reading the master password from an environment variable creates a real secret-exposure risk because environment variables are often inherited by child processes, captured by CI/CD systems, dumped in crash reports, or viewable through process inspection in some environments. In a password manager context, exposing the master password compromises the entire vault, making this more sensitive than ordinary application credentials.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The help output claims the skill supports backup, restore, and config commands, but the main() command dispatcher only implements init/add/get/update/change-password/search/list/generate/check-strength/status/lock/unlock/delete/help. This is an active contradiction between the user-facing documentation and the actual behavior of the program.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The help text instructs users to supply a master password on the command line even though the code comments indicate this is no longer supported and such usage is insecure. Command-line arguments are commonly exposed via shell history, process listings, logging, and audit tooling, so documenting this pattern materially increases the chance that users disclose their master password.

Content

No source excerpt is available for this finding.