Back to skill

Security audit

Vault Client

Security checks for vulnerabilities and agentic risk

Overview

This Vault client has a coherent purpose, but it persists Vault credentials and cached secrets locally and modifies future agent instructions in ways users should review before installing.

Review this before installing. Use only a least-privilege, short-lived Vault token; require HTTPS with a valid certificate; avoid tls.verify:false and http:// addresses; treat ~/.openclaw/vault.json and ~/.openclaw/vault-cache.json as sensitive files; clear the cache when done; and inspect any AGENTS.md changes before allowing them to affect future sessions.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vault.js:34
Finding
Vault credentials and cached secrets are stored without restrictive file permissions## Vulnerability Details **File Location**: `scripts/vault.js:34-36` and `scripts/vault.js:87-89` **Vulnerability Type**: Insecure storage of sensitive information **Risk Level**: High ### Vulnerable Code Configuration writing at `scripts/vault.js:34-36`: ```js function saveConfig(cfg) { fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true }); fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2)); } ``` Cache writing at `scripts/vault.js:87-89`: ```js function saveCache(cache) { fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2)); } ``` ### Technical Analysis The configuration file contains the Vault authentication token, and the cache file contains complete plaintext secret values retrieved from Vault. Both files are written without an explicit restrictive mode such as `0600`. Node.js therefore creates these files using permissions derived from the process umask. In environments with a permissive or incorrectly configured umask, other local users or processes may be able to read the files. The code also does not inspect or repair the permissions of existing files. The cache increases the exposure scope because retrieved API keys, database credentials, and other secrets remain on disk until manually removed, even after their configured cache expiration time. Cache expiration only prevents the application from using stale entries; it does not erase expired values from the file. ### Attack Path 1. A user runs `vault.js setup`, causing the Vault token to be written to `~/.openclaw/vault.json`. 2. The user runs `vault.js get`, causing retrieved secret values to be written to `~/.openclaw/vault-cache.json`. 3. The files are created under the permissions allowed by the ambient process umask. 4. Another local account or compromised process reads one or both files if their resulting permissions permit access. 5. The attacker directly uses cached credentials or submits the stolen V ...[truncated 746 chars]
Remediation
## Remediation Suggestions - Create both sensitive files with owner-only permissions: ```js fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2), { mode: 0o600 }); fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2), { mode: 0o600 }); ``` - Apply `fs.chmodSync(file, 0o600)` after writing so existing files with unsafe permissions are repaired. - Ensure `~/.openclaw` is accessible only to its owner, preferably with mode `0700`. - Use atomic writes through a securely created temporary file in the same protected directory, followed by a rename. - Refuse or safely handle symbolic links to reduce the risk of writing sensitive data to an unintended target. - Consider disabling persistent secret caching by default. If caching is required, remove expired entries from disk and provide a command that securely clears the cache. - Where feasible, store the Vault token through an operating-system credential store or secret service rather than a plaintext JSON file.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vault.js:41
Finding
Vault tokens and secrets can be transmitted over unauthenticated or unencrypted connections## Vulnerability Details **File Location**: `scripts/vault.js:41-66`; insecure configuration is documented at `SKILL.md:55` **Vulnerability Type**: Improper transport security for credentials and secret data **Risk Level**: High ### Vulnerable Code ```js function vaultRequest(cfg, method, urlPath, body = null) { return new Promise((resolve, reject) => { const url = new URL(urlPath, cfg.address); const isHttps = url.protocol === 'https:'; const lib = isHttps ? https : http; const token = cfg.auth?.token || ''; const options = { hostname: url.hostname, port: url.port || (isHttps ? 443 : 80), path: url.pathname + url.search, method, headers: { 'X-Vault-Token': token, 'Content-Type': 'application/json', }, timeout: 8000, // allow self-signed certs on internal Vault rejectUnauthorized: cfg.tls?.verify !== false, }; ``` The accompanying documentation states: ```md Set `tls.verify: false` for internal Vault with self-signed certs. ``` ### Technical Analysis The client accepts an `http://` Vault address and automatically uses Node.js's plaintext HTTP implementation. The `X-Vault-Token` header and all request and response bodies are consequently transmitted without encryption. For HTTPS connections, setting `tls.verify` to `false` disables certificate validation through `rejectUnauthorized: false`. Encryption without peer authentication does not protect against an active man-in-the-middle attacker because the attacker can present an arbitrary certificate and impersonate the Vault server. Every request includes the Vault token, including secret reads, writes, listing operations, and token-management calls. Secret values returned by reads and submitted by writes are therefore exposed when transport security is disabled. ### Attack Path 1. A user configures an `http://` Vault address ...[truncated 1208 chars]
Remediation
## Remediation Suggestions - Reject all non-HTTPS Vault addresses by default. - If plaintext HTTP is needed for development, restrict it to explicit loopback addresses and require a deliberate insecure-development override. - Remove the recommendation to set `tls.verify` to `false`. - Add support for a private certificate authority file, for example through an explicit `tls.ca_file` setting passed to the HTTPS request as trusted CA material. - Keep `rejectUnauthorized` enabled in normal operation and fail closed when certificate validation fails. - Validate the configured protocol and transport settings during setup and before every request. - Display a prominent warning and require explicit confirmation if any insecure override is retained. - Document secure deployment requirements, including valid server certificates, hostname verification, and protection against untrusted network paths.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/vault.js:263
Finding
Interactive setup echoes the Vault authentication token in plaintext## Vulnerability Details **File Location**: `scripts/vault.js:263` **Vulnerability Type**: Sensitive credential exposure through terminal input **Risk Level**: Medium ### Vulnerable Code ```js const token = await ask(`Vault token [${existing.auth?.token ? '(existing)' : 'hvs.xxx'}]: `); ``` The prompt is implemented using the ordinary readline interface: ```js const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const ask = (q) => new Promise(resolve => rl.question(q, resolve)); ``` ### Technical Analysis `readline.question` does not conceal user input. A Vault token entered during setup is visibly echoed to the terminal. Although the token is not intentionally printed after submission, terminal echo can expose it through shoulder surfing, screen sharing, terminal session recording, remote administration logs, or captured demonstrations. Vault tokens are bearer credentials and can generally be replayed without knowledge of another password. ### Attack Path 1. A user runs `vault.js setup`. 2. The setup wizard asks the user to enter a Vault token. 3. The token appears visibly while it is typed. 4. A nearby observer, screen-sharing participant, or terminal-recording system captures the token. 5. The observer submits the captured token to the Vault API. 6. The observer performs operations allowed by the token until it expires or is revoked. ### Impact Assessment The attacker obtains the same Vault authorization granted to the exposed bearer token. Depending on its policies, this may permit reading secrets, listing paths, updating values, or renewing the token. The direct scope is Vault access rather than local operating-system privilege. However, secrets obtained from Vault may enable access to databases, APIs, cloud infrastructure, and other systems.
Remediation
## Remediation Suggestions - Replace the ordinary readline token prompt with a hidden-input implementation that suppresses terminal echo. - Restore terminal state reliably on success, interruption, and exceptions. - Permit reading the token from a protected file descriptor or operating-system credential store for automated setup. - Do not accept the token as a command-line argument because arguments may be exposed through shell history and process listings. - Warn users not to enter tokens while screen sharing or in recorded terminal sessions. - After suspected exposure, revoke the affected token and issue a replacement with the minimum required Vault policies and a limited lifetime.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Missing User Warnings

High
Confidence
98% confidence
Finding
The documentation advises setting `tls.verify: false` for self-signed certificates without a strong warning about the security consequences. Disabling certificate verification removes server identity validation and exposes Vault traffic and tokens to man-in-the-middle attacks, which is severe given this skill handles secrets.

Missing User Warnings

High
Confidence
98% confidence
Finding
Retrieved secrets are cached to disk in ~/.openclaw/vault-cache.json, creating local plaintext persistence of sensitive material outside Vault's access controls and audit boundaries. Anyone with filesystem access, backup access, or malware on the host may recover API keys, credentials, or other secrets even after the Vault session ends.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes shell commands (`node .../vault.js`) but does not declare an explicit tool scope such as `permissions` or `allowed-tools`. That creates an authorization gap where an agent may be able to execute shell-capable behavior without clear policy boundaries, which is especially sensitive for a secret-management skill.

Session Persistence

Medium
Category
Rogue Agent
Content
---
name: vault-client
description: Hashicorp Vault client for OpenClaw agents. Read and write secrets from a Vault server without raw curl commands or hardcoded tokens. Use when reading API keys, DB credentials, or any secret stored in Hashicorp Vault; checking token expiry; rotating secrets; or configuring Vault access for the first time. NOT for the zuiho-kai local Vault skill (that is a different, local-only tool).
---

# vault-client
Confidence
60% 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.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The setup flow stores Vault address, token, and mount in `~/.openclaw/vault.json` and modifies `AGENTS.md`, but the documentation does not clearly warn that credentials and configuration will persist on disk across sessions. Persisted secrets increase the chance of local credential exposure through filesystem compromise, backups, logs, or accidental sharing.

External Transmission

Medium
Category
Data Exfiltration
Content
**Get a token via AppRole:**
```bash
curl -s -X POST https://vault.example.com:8200/v1/auth/approle/login \
  -d '{"role_id":"<role_id>","secret_id":"<secret_id>"}' | \
  node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.auth.client_token)"
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -s -X POST https://vault.example.com:8200/v1/auth/kubernetes/login \
  -d "{\"role\":\"my-role\",\"jwt\":\"$TOKEN\"}" | \
  node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.auth.client_token)"
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Session Persistence

Medium
Category
Rogue Agent
Content
* Usage:
 *   vault.js check                        # connectivity + token expiry
 *   vault.js get <path> [key]             # read secret (or single key)
 *   vault.js put <path> key=value ...     # write secret
 *   vault.js list <path>                  # list keys at path
 *   vault.js token-info                   # show token details + expiry
 *   vault.js token-renew                  # renew token
Confidence
60% 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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The setup wizard collects a Vault token and stores it in plaintext in ~/.openclaw/vault.json without warning, permission hardening, or safer credential storage. A local compromise, shared account, backup leak, or permissive file mode could expose the token and allow unauthorized Vault access.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The setup routine performs behavior outside the stated scope of a Vault client by appending instructions into a local AGENTS.md file. This creates an undocumented workspace-modification side effect that can influence future agent behavior and expands trust from secret access into persistent instruction injection.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Appending to AGENTS.md gives the skill persistence over future workspace instructions, which is not necessary for reading or writing Vault secrets. In an agent ecosystem, modifying an instruction file is security-sensitive because it can steer later agent actions, normalize fallback behaviors, or broaden the tool's influence beyond its declared purpose.

Static analysis

No suspicious patterns detected.