Back to skill

Security audit

Vault

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local password vault, but it needs Review because its credential-handling and storage-file behavior are too weak for a tool meant to protect secrets.

Review before installing if you plan to store real passwords or API keys. Use a strong master key, avoid typing secrets directly into logged shells, keep the vault path at the default unless you understand the filesystem risks, set restrictive permissions yourself, and keep backups because removal and file corruption can lose stored entries.

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

T09 · Insecure Skill Coding Practices

Error
Location
index.js:79
Finding

Unrestricted Storage Path and Insecure Vault File Handling

Content
View full analysis

Vulnerability Details

File Location: index.js:79-102, with configuration input at index.js:161-162
Vulnerability Type: Path traversal, symbolic-link following, insecure file permissions, and non-atomic credential storage
Risk Level: High

Vulnerable Code

js
class VaultStorage {
  constructor(storagePath, encryption) {
    this.storagePath = join(homedir(), storagePath);
    this.encryption = encryption;
  }

  async ensureStorage() {
    const dir = dirname(this.storagePath);
    if (!existsSync(dir)) {
      await mkdir(dir, { recursive: true });
    }
    if (!existsSync(this.storagePath)) {
      await writeFile(this.storagePath, JSON.stringify({}, null, 2));
    }
  }

  async load() {
    await this.ensureStorage();
    const content = await readFile(this.storagePath, 'utf-8');
    return JSON.parse(content);
  }

  async save(data) {
    await this.ensureStorage();
    await writeFile(this.storagePath, JSON.stringify(data, null, 2));
  }
}

The path is obtained directly from plugin configuration:

js
const config = api.getConfig() || {};
const storagePath = config.storageFile || '.vault/passwords.json';

Technical Analysis

The storageFile option is documented as a path relative to the user's home directory, but the implementation does not enforce that restriction. Passing the value to join(homedir(), storagePath) does not prevent .. components from resolving outside the home directory.

The implementation also uses ordinary filesystem reads and writes without checking whether the storage file or any parent component is a symbolic link. Consequently, a pre-positioned symlink can redirect vault operations to another file accessible to the OpenClaw process.

Files and directories are created without explicit restrictive modes. Their effective permissions therefore depend on the process umask, even though the documentation recommends m ...[truncated 2147 chars]

Remediation
View remediation

Remediation Suggestions

  1. Constrain storage to a dedicated directory

    • Resolve the configured value against a fixed vault root such as ~/.vault.
    • Reject absolute paths, .. traversal, null bytes, and any resolved path outside that root.
    • Compare normalized paths using path.resolve() and path.relative() before filesystem access.
  2. Defend against symbolic links

    • Inspect path components with lstat.
    • Reject symbolic links for the vault directory and storage file.
    • Where supported, open files with flags that prevent symlink following and use file descriptors for subsequent operations.
    • Verify file ownership before reading or replacing an existing vault.
  3. Apply restrictive permissions automatically

    • Create the vault directory with mode 0700.
    • Create the vault file and temporary files with mode 0600.
    • Validate and, where appropriate, correct permissions on existing storage.
    • Do not rely solely on the process umask or manual instructions.
  4. Use atomic and serialized updates

    • Serialize modifications with an appropriate lock.
    • Write the complete JSON document to an exclusively created temporary file in the same directory.
    • Flush the temporary file, apply mode 0600, and atomically rename it over the original.
    • Flush the containing directory where supported to improve crash consistency.
    • Maintain a securely permissioned backup or recovery strategy.
  5. Validate storage contents and fail safely

    • Enforce a schema for parsed vault records.
    • Set reasonable file-size limits.
    • Avoid modifying a target if ownership, type, path containment, permissions, or schema validation fails.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (10)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares it requires environment access via VAULT_MASTER_KEY but does not explicitly scope or declare tool permissions such as permissions or allowed-tools. In an agent setting, missing scope boundaries can cause the runtime to grant broader-than-intended access or make secret handling assumptions implicit rather than auditable.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documentation instructs users to pass secrets directly as command-line arguments (for example vault gemini sk-abc123xyz). Secrets provided this way may be exposed through shell history, terminal logs, process listings, audit systems, or CI logs, undermining the benefit of encrypting them at rest.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 120)May include surrounding context.

md
**Security Best Practices**:
- Use a strong, unique master key (minimum 32 characters recommended)
- Store master key securely (environment variable or secure config)
- Set strict file permissions: `chmod 600 ~/.vault/passwords.json`
- Add `.vault/` to your `.gitignore`
- Never commit your master key to version control
- Use system-level disk encryption for additional protection

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
**Security Best Practices**:
- Use a strong, unique master key (minimum 32 characters recommended)
- Store master key securely (environment variable or secure config)
- Set strict file permissions: `chmod 600 ~/.vault/passwords.json`
- Add `.vault/` to your `.gitignore`
- Never commit your master key to version control
- Use system-level disk encryption for additional protection

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The remove command deletes stored password entries immediately and only reports success after the fact. There is no confirmation prompt, pre-action warning, or other user disclosure indicating that an irreversible deletion will occur.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file contains core usage and setup instructions in Chinese after an English introduction, which effectively imposes a language requirement on users who may not read Chinese. The file does not provide an opt-in language choice or explain that the skill is intended for a Chinese-speaking audience.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The markdown describes vault ... remove as a normal operation but does not warn that deleting a stored credential may be irreversible, especially if no backup exists. For a credential-storage tool, omission of a user warning around deletion can affect user data integrity.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

Natural-language comments and command documentation at the top of the file are presented in Chinese, while the runtime skill description is in English, with no indication that language is configurable or intentionally region-specific. This creates a locale/language policy concern because the skill content assumes a language choice without explicit user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The code accesses process.env.VAULT_MASTER_KEY, which is a sensitive secret source, but the registered skill description is only Password management tool and does not warn users that the skill depends on and reads a master key from environment or config. For code files, sensitive environment variable access should have some form of user disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest presents user-facing description text in Chinese on L06 and L14 while other UI strings are in English, with no indication that the user can choose a preferred language or locale. This creates a language-policy concern because the skill exposes fixed-language content without documenting an opt-in or locale constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.