Back to skill

Security audit

vector-memory

Security checks for vulnerabilities and agentic risk

Overview

This memory-search skill is mostly purpose-aligned, but it contains unsafe command execution and file-reading flaws that could expose local files or run unintended commands.

Review before installing. The local semantic-memory goal is understandable, but install only from a trusted, pinned source; avoid the curl | bash path; and fix or wait for fixes to command execution and file path containment before using it on a workspace with secrets or sensitive files.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T03 · Remote Payload Retrieval and Execution

Error
Location
README.md:35
Finding
Documented Pipe-to-Shell Installation Executes Mutable Remote Code<![CDATA[ ## Vulnerability Details **File Location**: `README.md:35-38`; duplicated in `skills/vector-memory/README.md:40-43` and referenced by `install.sh:1-3` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: High ### Complete Code Snippet ```bash ### From GitHub ```bash curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash ``` ``` The same installation pattern is documented in the Skill README: ```bash ### From GitHub ```bash curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash ``` ``` The installer itself advertises the same invocation: ```bash #!/bin/bash # One-line installer for Vector Memory # Usage: curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash ``` ### Technical Analysis The installation instructions retrieve a shell script from a mutable `main` branch and immediately pass its contents to Bash. The user has no opportunity to inspect the effective script, and the command performs no checksum, signature, release-tag, or commit verification. The URL contains the placeholder `YOUR_USERNAME`, so it is not a functional or verifiably trusted source as shipped. If replaced with an actual account, the security of installation depends entirely on the continued integrity of that account and repository. The payload executed by users can also differ from the version reviewed by an auditor. This behavior is not necessary for the declared local memory-search functionality. A downloaded release archive or reviewed local installer would provide the same functionality without executing mutable network content directly. ### Attack Path 1. A user follows the documented GitHub installation command. 2. The shell retrieves the current contents of `install.sh` from the repository's `main` branch. 3. The repository owner, a compromised account, or another party controlling the substitu ...[truncated 670 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove all `curl | bash` installation instructions. - Publish immutable, versioned release archives rather than installing from `main`. - Replace the placeholder repository owner with an authenticated and documented project location. - Instruct users to download the installer to disk and inspect it before execution. - Publish a SHA-256 digest and preferably a cryptographic signature for each release. - Pin installation commands to a release tag and immutable commit. - Prefer installation through ClawHub or another package mechanism that provides integrity verification and version pinning. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
vector-memory/smart_memory.js:95
Finding
Shell Command Injection Through Interpolated Tool Arguments<![CDATA[ ## Vulnerability Details **File Location**: `vector-memory/smart_memory.js:95-105`; also present in `vector-memory/memory.js:21-32` and exposed through `skills/vector-memory/skill.json:8-20` **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Complete Code Snippet ```javascript async function vectorMemorySearch(query, maxResults = 5) { try { const result = execSync( `node vector-memory/vector_memory_local.js --search ${JSON.stringify(query)} --max-results ${maxResults}`, { cwd: WORKSPACE, encoding: 'utf-8', timeout: 30000 } ); ``` The vulnerable function is exposed through a shell command template in the manifest: ```json { "name": "memory_search", "description": "Search memory files with automatic method selection. Uses vector embeddings (semantic search) if indexed, otherwise falls back to built-in keyword search. Zero configuration required.", "command": "node {{workspace}}/vector-memory/smart_memory.js --search \"{{query}}\" --max-results {{max_results|5}}", "args": { "query": { "type": "string", "description": "The search query - natural language, concepts, or keywords", "required": true }, "max_results": { "type": "number", "description": "Maximum number of results to return", "default": 5 } } } ``` The alternate wrapper repeats the unsafe construction: ```javascript const result = execSync( `node vector-memory/vector_memory_local.js --search ${JSON.stringify(query)} --max-results ${maxResults}`, { cwd: WORKSPACE, encoding: 'utf-8', timeout: 30000 } ); ``` ### Technical Analysis `execSync()` receives a string and therefore invokes a shell. The search query and result limit are concatenated into that shell command. `JSON.stringify()` is a JSON encoder, not a shell escaping mechanism. For example, a query containing ...[truncated 1699 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not pass interpolated strings to `execSync()`. - Invoke Node directly with an argument array, for example: ```javascript import { execFileSync } from 'child_process'; const limit = Number.parseInt(maxResults, 10); if (!Number.isInteger(limit) || limit < 1 || limit > 100) { throw new TypeError('Invalid maxResults'); } const result = execFileSync( process.execPath, [ path.join(WORKSPACE, 'vector-memory', 'vector_memory_local.js'), '--search', String(query), '--max-results', String(limit) ], { cwd: WORKSPACE, encoding: 'utf-8', timeout: 30000 } ); ``` - Prefer direct JavaScript imports over starting a subprocess. - Configure tool bindings to pass structured arguments rather than constructing shell commands. - Validate `max_results`, line numbers, and all other numeric parameters against strict bounds. - Treat framework-level escaping as defense in depth rather than the primary control. - Add automated tests using quotes, backticks, `$()`, semicolons, newlines, and other shell metacharacters. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
vector-memory/smart_memory.js:148
Finding
Memory Retrieval Permits Workspace Escape and Arbitrary File Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `vector-memory/smart_memory.js:148-170`; similar logic appears in `vector-memory/memory.js:52-75` and `vector-memory/vector_memory_local.js:232-245` **Vulnerability Type**: Path traversal and unauthorized file access **Risk Level**: High ### Complete Code Snippet ```javascript export function memoryGet(filePath, from, lines) { try { const fullPath = path.join(WORKSPACE, filePath); if (!fs.existsSync(fullPath)) { return null; } const content = fs.readFileSync(fullPath, 'utf-8'); const allLines = content.split('\n'); const lineCount = parseInt(lines) || 50; const startLine = parseInt(from) || 1; const slice = allLines.slice(startLine - 1, startLine - 1 + lineCount); return { path: filePath, from: startLine, content: slice.join('\n') }; } catch (error) { console.error(`Memory get error: ${error.message}`); return null; } } ``` The tool exposes `filePath` to callers: ```json { "name": "memory_get", "description": "Get full content from a memory file by path and line range.", "command": "node {{workspace}}/vector-memory/smart_memory.js --get \"{{file_path}}\" {{from_line}} {{line_count}}", "args": { "file_path": { "type": "string", "description": "Path to memory file (e.g., MEMORY.md or memory/2026-02-04.md)", "required": true } } } ``` ### Technical Analysis The function joins an untrusted path to the workspace but does not verify that the normalized result remains within an authorized memory directory. Relative traversal components can therefore escape the workspace. The code also does not reject absolute paths or protect against symbolic links resolving outside the approved root. The declared purpose is to retrieve `MEMORY.md` or files under the workspace's `memory/` directory. Allowing ac ...[truncated 1096 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Restrict retrieval to `MEMORY.md` and Markdown files beneath the workspace's `memory/` directory. - Reject absolute paths, null bytes, and explicit traversal components. - Resolve and canonicalize both the requested path and allowed roots: ```javascript const workspaceRoot = fs.realpathSync(WORKSPACE); const memoryRoot = fs.realpathSync(path.join(workspaceRoot, 'memory')); const requested = fs.realpathSync(path.resolve(workspaceRoot, filePath)); const isMainMemory = requested === path.join(workspaceRoot, 'MEMORY.md'); const isUnderMemory = requested.startsWith(memoryRoot + path.sep) && requested.endsWith('.md'); if (!isMainMemory && !isUnderMemory) { throw new Error('Path is outside permitted memory locations'); } ``` - Check canonical paths after symbolic-link resolution. - Apply reasonable upper bounds to `from` and `lines` to prevent excessive reads. - Ensure the tool process runs under a dedicated, least-privileged account with no access to unrelated secrets. - Add traversal tests covering `../`, absolute paths, mixed separators, and symlink escapes. ]]>

T08 · Insecure Dependencies

Warning
Location
install.sh:39
Finding
Installer Retrieves Unpinned Source and Executes an Unlocked Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:39-69`; related dependency declaration at `vector-memory/package.json:7-9` **Vulnerability Type**: Insecure software supply chain **Risk Level**: Medium ### Complete Code Snippet ```bash # Clone or download echo "📥 Downloading Vector Memory..." REPO_URL="https://github.com/YOUR_USERNAME/vector-memory-openclaw" if command -v git &> /dev/null; then # Git available - clone cd /tmp rm -rf vector-memory-temp 2>/dev/null || true git clone --depth 1 "$REPO_URL.git" vector-memory-temp # Copy files cp -r vector-memory-temp/skills/vector-memory "$WORKSPACE/skills/" cp -r vector-memory-temp/vector-memory "$WORKSPACE/" rm -rf vector-memory-temp else # No git - download tarball cd /tmp curl -L "$REPO_URL/archive/main.tar.gz" | tar xz cp -r vector-memory-openclaw-main/skills/vector-memory "$WORKSPACE/skills/" cp -r vector-memory-openclaw-main/vector-memory "$WORKSPACE/" rm -rf vector-memory-openclaw-main fi echo "✅ Files installed" echo "" # Install dependencies echo "📦 Installing dependencies..." cd "$WORKSPACE/vector-memory" npm install --silent ``` The package uses a version range and the project contains no lockfile: ```json "dependencies": { "@xenova/transformers": "^2.17.2" } ``` ### Technical Analysis The installer clones or downloads the mutable `main` branch without pinning a commit and without verifying a checksum or signature. It then runs `npm install --silent` on the downloaded package. No package lockfile is included, and the dependency is specified with a caret range. Consequently, installations performed at different times may resolve different transitive dependency trees. NPM installation may also execute dependency lifecycle scripts unless explicitly disabled. The fallback archive is streamed directly into `tar`, so the archive is neither retained for inspection nor verified before extraction. These design choices allo ...[truncated 1049 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin the repository download to an immutable commit or signed release tag. - Publish and verify checksums or signatures before extracting source archives. - Download archives to a newly created private temporary directory rather than streaming them directly into `tar`. - Add and commit a package lockfile. - Replace the caret range with a reviewed exact dependency version. - Use `npm ci` for reproducible installation. - Use `npm ci --ignore-scripts` if the dependency tree does not require lifecycle scripts; otherwise explicitly audit every required script. - Remove `--silent` so security-relevant installation warnings remain visible. - Generate and verify a software bill of materials and dependency provenance for releases. ]]>

T08 · Insecure Dependencies

Warning
Location
vector-memory/vector_memory_local.js:21
Finding
Embedding Model Is Downloaded at Runtime Without Project-Level Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `vector-memory/vector_memory_local.js:21-41` **Vulnerability Type**: Unverified runtime dependency retrieval **Risk Level**: Medium ### Complete Code Snippet ```javascript const VECTOR_DB_PATH = '/config/.openclaw/workspace/vector-memory/vectors_local.json'; const MODEL_NAME = 'Xenova/all-MiniLM-L6-v2'; // Lazy-loaded pipeline let embedder = null; async function getEmbedder() { if (embedder) return embedder; console.error('Loading embedding model (first time, ~80MB)...'); // Dynamic import for ES modules const { pipeline, env } = await import('@xenova/transformers'); // Use local cache in workspace env.cacheDir = '/config/.openclaw/workspace/.cache/transformers'; embedder = await pipeline('feature-extraction', MODEL_NAME, { quantized: true, // Smaller, faster }); console.error('Model loaded!'); return embedder; } ``` ### Technical Analysis The first vector synchronization requests model assets by a model name rather than by a project-verified artifact digest or immutable revision. The documentation discloses that approximately 80 MB will be downloaded, so the network access is related to the declared semantic-search function. However, the project itself does not enforce a checksum, signature, or pinned model revision. The downloaded assets are cached under the OpenClaw workspace and subsequently trusted by the embedding runtime. This creates a supply-chain dependency beyond the reviewed repository. ### Attack Path 1. A user runs the initial vector synchronization. 2. Transformers.js resolves `Xenova/all-MiniLM-L6-v2` through its configured remote model source. 3. A compromised upstream account, distribution service, or network trust chain supplies altered model assets. 4. The runtime caches and loads those assets. 5. Depending on the affected asset format and parser behavior, this may cause manipulated retrieval behavior or expo ...[truncated 506 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin the model to an immutable upstream revision. - Publish expected SHA-256 hashes for every required model asset and verify them before loading. - Prepackage reviewed model assets in a signed release where licensing and distribution constraints allow. - Document the exact network host, model revision, files, and expected sizes used during first synchronization. - Fail closed when an asset does not match the expected digest. - Protect the cache directory from modification by unrelated users or processes. - Consider disabling remote model retrieval after the verified initial installation. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (40)

Chaining Abuse

High
Category
Tool Misuse
Content
### From GitHub
```bash
curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash
```

### Manual
Confidence
99% confidence
Finding
The `| bash` construct creates an immediate execution chain from downloaded content to the shell, eliminating any opportunity for inspection and amplifying the impact of repository or transport compromise. Because this is an installation path for a developer-facing skill, it directly normalizes unsafe command execution and can lead to full local code execution.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Claiming 'works immediately' and 'no setup required' while requiring explicit sync/indexing and possible model download/cache setup is a material behavior mismatch. In the context of an installable skill that can run shell commands, this can cause users to trigger unexpected setup, downloads, or state changes they did not knowingly approve.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Claiming 'works immediately' and 'no setup required' while requiring explicit sync/indexing and possible model download/cache setup is a material behavior mismatch. In the context of an installable skill that can run shell commands, this can cause users to trigger unexpected setup, downloads, or state changes they did not knowingly approve.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Claiming 'works immediately' and 'no setup required' while requiring explicit sync/indexing and possible model download/cache setup is a material behavior mismatch. In the context of an installable skill that can run shell commands, this can cause users to trigger unexpected setup, downloads, or state changes they did not knowingly approve.

Ae1

High
Category
analysis-evasion
Content
node vector-memory/smart_memory.js --sync
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node vector-memory/smart_memory.js --sync
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node vector-memory/smart_memory.js --sync
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node vector-memory/smart_memory.js --sync
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node vector-memory/smart_memory.js --sync
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `memory.js` | OpenClaw wrapper |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Chaining Abuse

High
Category
Tool Misuse
Content
#!/bin/bash
# One-line installer for Vector Memory
# Usage: curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash

set -e
Confidence
98% confidence
Finding
The explicit '| bash' chaining removes any review boundary between untrusted network content and code execution, making compromise of the hosting source immediately exploitable. In the context of a skill installer that later clones a repo and runs npm install, this pattern is especially dangerous because it compounds trust in multiple remote execution stages.

Chaining Abuse

High
Category
Tool Misuse
Content
### From GitHub
```bash
curl -sL https://raw.githubusercontent.com/YOUR_USERNAME/vector-memory-openclaw/main/install.sh | bash
```

### Manual
Confidence
99% confidence
Finding
The `| bash` pipeline is a classic unsafe command-chaining pattern because it turns downloaded text directly into shell commands without any review or verification step. In a README for a developer tool, this materially increases danger since installation is a high-trust moment and users may execute the command verbatim, enabling immediate arbitrary command execution.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The README instructs users to execute a remote installer directly with `curl ... | bash` and provides no warning or verification steps. This is dangerous because any compromise of the GitHub account, repository, branch, or network path can result in arbitrary shell command execution on the user's machine.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises commands that invoke shell execution and rely on environment variables, but the manifest does not declare any tool scope such as permissions or allowed-tools. That weakens least-privilege controls and makes it easier for an installer or agent runtime to grant broader execution capability than users expect.

Rp1

Medium
Category
MCP Rug Pull
Confidence
87% confidence
Finding
Using `npx clawhub install vector-memory` without a pinned version permits installation of whatever version is current at execution time. This creates a supply-chain risk where a compromised or malicious updated package could be fetched and executed unexpectedly.

Description-Behavior Mismatch

Medium
Confidence
83% confidence
Finding
The manifest describes a memory-search skill that works immediately and focuses on semantic/vector fallback behavior, but this installer also fetches code from GitHub and runs npm dependency installation. While expected for installation machinery, these operations materially exceed the behavior implied by the manifest description of the skill itself and 'no setup required'.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script deletes the /tmp/vector-memory-temp directory via rm -rf, but the only surrounding user-facing messages describe downloading and installation rather than removal of files. Although temporary cleanup is common, this is still a destructive filesystem action with no explicit disclosure of the deletion step.

Rp1

Medium
Category
MCP Rug Pull
Confidence
87% confidence
Finding
The README instructs users to run `npx clawhub install vector-memory` without pinning a specific package version. This can lead to non-reproducible installs and increases supply-chain risk if a later compromised or malicious version of the package is published and then implicitly trusted by users.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
The README tells users to fetch a remote script and pipe it directly into `bash`, which executes unreviewed network content immediately on the local system. This is dangerous because any compromise of the GitHub account, repository, branch, or network path can turn installation into arbitrary code execution with the user's privileges.

Vague Triggers

Medium
Confidence
87% confidence
Finding
This is a manifest file, so vague-trigger checks apply. The description and tool text emphasize broad phrases like 'Zero configuration - works immediately after install' and 'natural language, concepts, or keywords' but do not define when this skill should or should not be invoked, which can cause unintended activation overlap with general memory or search requests.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest says the skill 'falls back to built-in search otherwise' and that 'memory_search works immediately,' but memorySearch only invokes the vector backend and, on failure, logs an error and returns an empty array. There is no built-in search fallback path in this file, so the described behavior is not implemented here.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
memoryGet joins a user-controlled filePath with the workspace root but does not normalize and verify that the resolved path remains inside WORKSPACE. An attacker can supply traversal sequences such as ../ to read arbitrary files accessible to the process, which is especially dangerous in a memory/search skill because callers are expected to provide file paths and may expose configuration, secrets, or other sensitive host data.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The package description says "100% local vector memory using transformers.js embeddings" and the entrypoint name reinforces a local-only implementation. This conflicts with the skill manifest, which describes "automatic vector fallback" and immediate operation via built-in search when embeddings are unavailable, indicating broader behavior than the package documentation states.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
vector-memory/memory.js:23

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
vector-memory/smart_memory.js:97

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
vector-memory/references/pgvector.md:28