Back to skill

Security audit

MemVault

Security checks for vulnerabilities and agentic risk

Overview

MemVault appears to be a real long-term memory server, but its default install and deployment expose sensitive persistent memory too broadly.

Review before installing. Do not run the installer as-is on a sensitive machine; remove the curl-to-sh Ollama install path, bind services to 127.0.0.1 or a private network, add API authentication, replace default database credentials, and decide explicitly whether memory content may be sent to any non-local LLM endpoint.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/install.sh:35
Finding

Installer Downloads and Immediately Executes a Mutable Remote Script

Content
View full analysis
/dev/null; then warn "Ollama not found. Attempting install..." if [[ "$(uname)" == "Darwin" ]]; then brew install ollama 2>/dev/null || { warn "Auto-install failed. Install manually: https://ollama.com/download" warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env" } elif [[ "$(uname)" == "Linux" ]]; then curl -fsSL https://ollama.com/install.sh | sh fi fi ``` ### Technical Analysis The installer pipes an HTTPS response directly into `sh`. The downloaded program is not pinned to a version, inspected, signature-verified, or checked against a hard-coded cryptographic digest. Consequently, the effective code executed by the Skill can change after the packaged Skill has been reviewed. Installing a local LLM runtime supports the declared functionality, but immediate remote shell execution is not the least-privileged or minimum-risk installation method. The remote script executes with all privileges held by the user running `scripts/install.sh` and may itself invoke privilege-elevation mechanisms. ### Attack Path 1. A user follows the documented quick-start command, `bash scripts/install.sh`. 2. The installer determines that `ollama` is absent on a Linux host. 3. The installer requests the current content of `https://ollama.com/install.sh`. 4. A compromise of the distribution account, upstream hosting, or applicable TLS/DNS trust path changes the response. 5. The response is passed directly to `sh` without verification. 6. Attacker-controlled commands execute with the installer's host privileges. ### Impact Assessment Successful exploitation permits arbitrary command execution on the host under the installer user's account. If the installer is run as roo ...[truncated 208 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
docker-compose.yml:37
Finding

Unauthenticated Memory API Is Published on All Host Interfaces

Content
View full analysis
MemorizeResponse: """Store a conversation in long-term memory.""" ``` ```python @app.post("/retrieve", response_model=RetrieveResponse) async def retrieve(req: RetrieveRequest) -> RetrieveResponse: """Retrieve memories using strength-weighted vector search.""" ``` ```python @app.post("/decay") async def run_decay(decay_rate: float = 0.1, damping: float = 0.5, user_id: str = "default"): ``` ```python @app.get("/stats") async def memory_stats(user_id: str = "default"): ``` ### Technical Analysis Docker's short `ports` syntax publishes port 8002 on all host interfaces unless a host address is specified. The API provides no authentication middleware, API-key validation, or endpoint-level authorization. The caller supplies `user_id`, and database queries use it directly as the tenant selector. Although SQL values are parameterized, there is no verificati ...[truncated 1080 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
docker-compose.yml:3
Finding

PostgreSQL Is Exposed with Hard-Coded Default Administrator Credentials

Content
View full analysis
Remediation
View remediation

other

Warning
Location
memvault_server.py:67
Finding

Sensitive Memory Content Can Be Sent to a Configurable External LLM Endpoint

Content
View full analysis
dict[str, str]: """Batch translate summaries to target language via local LLM.""" import httpx if not summaries: return {} lines = [f"[{i}] {s}" for i, (_, s) in enumerate(summaries)] batch_text = "\n".join(lines) try: async with httpx.AsyncClient(timeout=60) as client: resp = await client.post( LLM_BASE_URL + "/chat/completions", json={ "model": LLM_MODEL, "messages": [ {"role": "system", "content": ( f"Translate the following numbered memory summaries to concise {target_lang}. " f"Output strictly one line per item: [number] translation\n" f"No explanations. If already in {target_lang}, output as-is." )}, {"role": "user", "content": batch_text} ], "temperature": 0.1, }, ) ``` The extraction service uses the same configurable endpoint: ```python llm_config = { "default": { "base_url": LLM_BASE_URL, "api_key": LLM_API_KEY, "chat_model": LLM_MODEL, "client_backend": "httpx", "embed_model": EMBEDDING_MODEL, }, ``` ### Technical Analysis Memory summaries are posted to `LLM_BASE_URL` during optional translation, and conversation extraction is configured to use the same LLM profile. The declared documentation allows operators to replace the local Ollama endpoint with an OpenAI-compatible third-party endpoint. ...[truncated 1250 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
memvault_server.py:275
Finding

Request-Controlled User Identifier Is Incorporated into a Temporary File Path

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Dependencies and Container Images Are Not Reproducibly Pinned

Content
View full analysis
=1.3.0 fastapi>=0.115.0 uvicorn>=0.32.0 pydantic>=2.12.0 sentence-transformers>=3.3.0 requests>=2.32.0 psycopg2-binary>=2.9.0 httpx>=0.28.0 # Production gunicorn>=23.0.0 python-dotenv>=1.0.0 ``` Mutable image tags are also used: ```dockerfile FROM python:3.13-slim AS base ``` ```yaml image: pgvector/pgvector:pg16 ``` ### Technical Analysis Lower-bound constraints permit future builds to install any later package version satisfying the constraint. No lock file or package hashes are provided. The container base and PostgreSQL image tags are mutable and are not pinned by digest. This does not prove that any current dependency is malicious. It creates a supply-chain and reproducibility weakness: rebuilding the same source at a later date can execute substantially different third-party code without a corresponding reviewed project change. ### Attack Path 1. An upstream package account, package release, container tag, or registry artifact is compromised or changes incompatibly. 2. A user runs the documented Docker build. 3. `pip` resolves newer packages allowed by the broad constraints, or Docker resolves a different image behind the same tag. 4. The unreviewed code is installed into the resulting image. 5. The code executes during package installation, image build, model loading, or service startup. ### Impact Assessment A compromised dependency can execute code during build or runtime with the privileges of the build environment or container. It can access application configuration, database credentials, memory contents, and reachable services. Container isolation limits default host access, but build environments and mounted credenti ...[truncated 29 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (57)

Tainted flow: 'EMBEDDING_URL' from os.environ.get (line 34, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · memvault_server.py (reported line 358)May include surrounding context.

python
import requests as req_lib
        import psycopg2

        embed_resp = req_lib.post(
            f"{EMBEDDING_URL}/embeddings",
            json={"input": req.query, "model": EMBEDDING_MODEL}, timeout=10,
        )

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a full long-term memory system for AI agents, but the supplied code only implements an embedding microservice. It loads a sentence-transformers model at startup and provides endpoints to convert text into vector embeddings. There is no database, persistence layer, recall/search over stored memories, decay scheduling, memory strength handling, statistics computation, or per-agent memory management. While embeddings could support a memory system, this code chunk itself is only a supporting component and does not match the declared primary purpose.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.example.txt (reported line 2)May include surrounding context.

text
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · memvault_server.py (reported line 31)May include surrounding context.

python
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 61)May include surrounding context.

sh
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 64)May include surrounding context.

sh
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 78)May include surrounding context.

sh
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 80)May include surrounding context.

sh
# MemVault Configuration
# Copy this to .env and customize as needed

# PostgreSQL (with pgvector extension)
MEMVAULT_DB_DSN=postgresql://postgres:postgres@127.0.0.1:5432/memvault

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 37)May include surrounding context.

sh
if [[ "$(uname)" == "Darwin" ]]; then
        brew install ollama 2>/dev/null || {
            warn "Auto-install failed. Install manually: https://ollama.com/download"
            warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env"
        }
    elif [[ "$(uname)" == "Linux" ]]; then
        curl -fsSL https://ollama.com/install.sh | sh

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 66)May include surrounding context.

sh
if [[ "$(uname)" == "Darwin" ]]; then
        brew install ollama 2>/dev/null || {
            warn "Auto-install failed. Install manually: https://ollama.com/download"
            warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env"
        }
    elif [[ "$(uname)" == "Linux" ]]; then
        curl -fsSL https://ollama.com/install.sh | sh

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/install.sh (reported line 67)May include surrounding context.

sh
if [[ "$(uname)" == "Darwin" ]]; then
        brew install ollama 2>/dev/null || {
            warn "Auto-install failed. Install manually: https://ollama.com/download"
            warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env"
        }
    elif [[ "$(uname)" == "Linux" ]]; then
        curl -fsSL https://ollama.com/install.sh | sh

External Script Fetching

High
Category
Supply Chain
Confidence
99% confidence
Finding

The command fetches an external script from ollama.com and executes it on the host. This is a classic external-script-fetching risk: any compromise of the remote script, DNS/TLS trust chain, or distribution path results in arbitrary host code execution during installation.

Content

Scanner excerpt · scripts/install.sh (reported line 40)May include surrounding context.

sh
warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env"
        }
    elif [[ "$(uname)" == "Linux" ]]; then
        curl -fsSL https://ollama.com/install.sh | sh
    fi
fi

Chaining Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The '| sh' chaining turns a network response directly into a shell interpreter, eliminating opportunities for inspection and validation. In an installer for a memory server, this significantly increases danger because users expect setup automation, making them more likely to run it without scrutinizing the fetched code.

Content

Scanner excerpt · scripts/install.sh (reported line 40)May include surrounding context.

sh
warn "Or set MEMVAULT_LLM_BASE_URL to an OpenAI-compatible endpoint in .env"
        }
    elif [[ "$(uname)" == "Linux" ]]; then
        curl -fsSL https://ollama.com/install.sh | sh
    fi
fi

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises shell, network, environment, and file-writing capabilities through its install and operational instructions, but it does not declare any tool scope or permission boundaries. That creates an authorization and transparency gap: an agent or reviewer cannot tell from the manifest what sensitive capabilities the skill expects, increasing the risk of unintended command execution or data handling.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Using broad triggers like "remember" and "recall" can cause the skill to activate in many normal conversations, including contexts where users did not intend persistent storage. In a memory skill, accidental invocation is more dangerous because it can lead to unsolicited retention of sensitive conversation content across sessions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly stores conversations, extracts facts, tracks access patterns, and supports multi-agent memory, yet it provides no clear privacy warning, consent model, retention guidance, or data sensitivity limitations. In context, this is significant because the core function is long-term persistence of user and agent content, which can expose sensitive personal, organizational, or cross-agent data if users are unaware of the storage model.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Add Ebbinghaus decay to your agent's cron:

text
0 3 * * *  curl -s -X POST 'http://127.0.0.1:8002/decay?user_id=YOUR_USER_ID'

TOOLS.md Snippet

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The compose file configures the memory service to call an external LLM endpoint and supplies an API key, which expands the component from a storage-focused memory server into a network-connected text-generation client. Because long-term memory systems handle sensitive prompts and stored content, this creates additional data exfiltration and prompt-handling risk that is not clearly reflected in the declared skill purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The configuration sets MEMVAULT_TRANSLATION_LANG to Chinese by default, which imposes a specific language/locale choice in natural-language behavior. There is no indication here of user opt-in or a documented region-specific justification for this default.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes persistent memory, decay, retrieval, statistics, and multi-agent tracking, but does not mention translating stored memories into another language. The code enables a translation feature that sends memory summaries to an LLM and updates the database with translated content, materially changing stored memories beyond the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The configuration sets the default translation target language to Chinese, and translated summaries are written back into stored memory when translation is enabled. This imposes a specific language choice by default rather than offering a user-selected locale or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The server sends stored memory summaries to an LLM service for translation, which creates a real confidentiality risk because persisted user memories may be disclosed to another service boundary. In this skill context, memory contents are likely sensitive by design, so forwarding them for translation without strong disclosure, consent, and trust constraints is more dangerous than in a generic text-processing service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Stored summaries are sent to embedding and translation services without explicit user-facing disclosure, which is a genuine privacy risk because memory data crosses service boundaries. Even when defaults point to localhost, these endpoints are operator-configurable and may be remote, so the exposure is meaningful in real deployments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Conversation data is persisted to local temporary storage without any visible disclosure or consent mechanism, creating a privacy and data-handling risk. Users and integrators may reasonably assume the server processes submissions directly rather than materializing them on disk, especially for sensitive memory content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.