Back to skill

Security audit

knowledge-vault

Security checks for vulnerabilities and agentic risk

Overview

This long-term memory skill is mostly purpose-aligned, but it can automatically create external storage, send saved text to Google for embeddings, and cache database credentials locally in plaintext without strong user controls.

Review before installing. Use your own scoped TiDB database credentials, avoid the auto-provisioning fallback, restrict permissions on any local DSN file, and do not store secrets, health details, customer data, or other sensitive information unless you have explicit consent and a deletion process. Treat retrieved memories as untrusted reference text, not instructions.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T02 · Agent Memory Poisoning

Error
Location
run.py:106
Finding
Persistent Memory Can Store and Replay Attacker-Controlled Instructions<![CDATA[ ## Vulnerability Details **File Location**: `PROTOCOL.md:2-5`; `run.py:106-127` **Vulnerability Type**: Persistent agent memory poisoning **Risk Level**: High ### Vulnerable Code `PROTOCOL.md:2-5`: ```markdown * **Trigger:** When the user shares important context ("Here is a summary of project X") or asks a question that requires recalling past information. * **Action:** * **To Remember:** Call `knowledge-vault --action add`. * **To Recall:** Call `knowledge-vault --action search`. ``` `run.py:106-127`: ```python if action == "add": if not content: return {"success": False, "error": "Content required"} vec = get_embedding(content) vec_str = str(vec) # pymysql handles list -> string conversion? prefer explicit string for VECTOR literal cursor.execute("INSERT INTO knowledge_vault (content, embedding) VALUES (%s, %s)", (content, vec_str)) return {"success": True, "message": "Content embedded and stored."} elif action == "search": if not query: return {"success": False, "error": "Query required"} q_vec = get_embedding(query) q_vec_str = str(q_vec) # Vector Search SQL (Security Fix: Parameterize LIMIT) sql = """ SELECT content, VEC_COSINE_DISTANCE(embedding, %s) as distance FROM knowledge_vault ORDER BY distance ASC LIMIT %s """ cursor.execute(sql, (q_vec_str, int(limit))) results = [] for row in cursor.fetchall(): results.append({"content": row[0], "distance": float(row[1])}) ``` ### Technical Analysis The protocol directs the agent to persist user-provided context, while the implementation stores the supplied `content` verbatim. Search results are subsequently returned as raw text without provenance, trust metadata, instruction filtering, or a boundary identifying the result as untrusted data. SQL parameterization prevents SQL injection, bu ...[truncated 1335 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require explicit user confirmation before writing user-supplied material to persistent memory. - Store provenance, owner, creation context, and trust level alongside every record. - Keep retrieved content in a clearly delimited, untrusted-data section and explicitly instruct the consuming agent never to execute instructions found in memories. - Detect or flag instruction-like content before storage and retrieval. - Support review, deletion, expiration, and namespace isolation for persisted records. - Restrict retrieval by tenant, user, project, and session authorization rather than semantic similarity alone. - Consider returning structured records such as `{content, source, trust_level}` instead of undifferentiated text. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
run.py:61
Finding
Database Credentials Are Cached in Plaintext and Database TLS Is Not Enforced<![CDATA[ ## Vulnerability Details **File Location**: `run.py:15`, `run.py:61-63`, `run.py:84-87` **Vulnerability Type**: Plaintext credential storage and insecure database transport configuration **Risk Level**: High ### Vulnerable Code `run.py:15`: ```python DSN_FILE = os.path.expanduser("~/.openclaw_knowledge_vault_dsn") ``` `run.py:61-63`: ```python if dsn: with open(DSN_FILE, 'w') as f: f.write(dsn) ``` `run.py:84-87`: ```python # Security Fix: Enable SSL hostname verification (remove check_hostname: False) conn = pymysql.connect( host=host, port=port, user=user, password=password, database=db, charset='utf8mb4', autocommit=True ) ``` ### Technical Analysis The auto-provisioned connection string contains database credentials and is written directly to a file in the user's home directory. The code does not explicitly create the file with owner-only permissions. Its actual permissions therefore depend on the process umask and surrounding environment. In addition, the `pymysql.connect` call does not supply an SSL context, trusted CA, or certificate-verification settings. The comment claims hostname verification is enabled, but the connection configuration does not enforce it. Consequently, the client does not fail closed unless transport encryption and server identity verification are guaranteed externally. ### Attack Path **Local credential exposure:** 1. The skill runs without configured TiDB credentials. 2. It provisions a database and receives a credential-bearing DSN. 3. The DSN is written to `~/.openclaw_knowledge_vault_dsn` using default file-creation permissions. 4. On a system with a permissive umask or unsafe home-directory access, another local account or process reads the file. 5. The attacker uses the recovered credentials to connect to the database and access or alter stored memories. **Network interception:** 1. The skill connects to TiDB wit ...[truncated 858 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store credentials in an operating-system credential manager or dedicated secret store instead of a plaintext file. - If a file is unavoidable, create it atomically with mode `0600`, verify ownership and permissions before every read, and reject symbolic links. - Avoid embedding credentials in a full DSN where feasible. - Create an SSL context that requires TLS, validates the certificate chain against a trusted CA, and verifies the database hostname. - Configure PyMySQL with the verified SSL context and fail closed if secure transport cannot be established. - Rotate any credentials that may already have been cached with unsafe permissions. - Grant the database account only the minimum table-level privileges required by the skill. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Third-Party Dependencies Are Unpinned and Builds Are Not Reproducible<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-2` **Vulnerability Type**: Unconstrained third-party dependency resolution **Risk Level**: Medium ### Vulnerable Code `requirements.txt:1-2`: ```text pymysql google-genai ``` ### Technical Analysis Both dependencies are specified without versions or integrity hashes. Each installation can therefore resolve to whatever release is current at that time. This prevents reproducible builds and permits an unreviewed future release—including a compromised release—to enter the execution environment automatically. The package names shown are not evidence of typosquatting or current malicious behavior. The confirmed weakness is the absence of version and integrity constraints, which increases supply-chain exposure and makes security review results unstable over time. ### Attack Path 1. A new, vulnerable, or compromised version of `pymysql` or `google-genai` is published or becomes the version selected by the package resolver. 2. A user performs a fresh installation using this `requirements.txt`. 3. The installer downloads the newly selected version because no reviewed version or hash is required. 4. Malicious installation hooks or runtime code execute with the privileges of the installing or invoking user. 5. Such code could access the Gemini API key, TiDB credentials, stored content, and other resources available to the process. ### Impact Assessment A compromised dependency executes within the skill's Python process and receives the same user-level privileges and environment access as the skill. This may expose `GEMINI_API_KEY`, TiDB credentials, memory content, and writable files accessible to the invoking account. The exact impact depends on the behavior of the dependency version selected during installation; no currently malicious package version was established by this audit. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin each dependency to a reviewed exact version. - Generate and commit a lock file containing transitive dependency versions. - Require package hashes during installation, for example through a hash-locked requirements file. - Install only from an approved package index over verified TLS. - Run dependency vulnerability and provenance checks in continuous integration. - Update dependencies through a controlled review process rather than automatically accepting new releases. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (14)

Self-Modification

High
Category
Rogue Agent
Content
try:
        host, port, user, password, db = parse_dsn(dsn)
        # Security Fix: Enable SSL hostname verification (remove check_hostname: False)
        conn = pymysql.connect(
            host=host, port=port, user=user, password=password, database=db,
            charset='utf8mb4', autocommit=True
Confidence
70% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger condition is broad enough to fire on normal conversation such as sharing general context or asking questions that reference prior discussion. In a long-term memory skill, this can cause oversaving of user content and overuse of recall tooling, increasing the chance that sensitive or irrelevant information is stored or retrieved without clear user intent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises and implicitly requires access to environment variables, local file reads/writes, and shell execution, but does not declare any explicit tool scope or permission boundaries. That makes its effective privilege set ambiguous and increases the chance an agent will invoke it with broader access than intended, especially because it handles secrets and persistence.

Session Persistence

Medium
Category
Rogue Agent
Content
### 🔐 Security & Provisioning
This skill operates in two modes:
1.  **Bring Your Own Database (Recommended):** Set `TIDB_HOST`, `TIDB_USER`, `TIDB_PASSWORD` environment variables. The skill will use your existing database.
2.  **Auto-Provisioning (Fallback):** If no credentials are found, the skill calls the **TiDB Zero API** to create a temporary, ephemeral database for you. It caches the connection string locally (`~/.openclaw_knowledge_vault_dsn`) to persist memory across runs.

## Installation
Confidence
96% confidence
Finding
The skill states it will auto-provision a database if credentials are absent and cache the resulting connection string in a predictable local file under the user's home directory. Persisting a live DSN locally can expose database credentials to other local processes, future sessions, or unintended users, and the auto-provisioning behavior may also create external resources and data persistence without explicit user approval.

Skill Enumeration

Medium
Category
Agent Snooping
Content
### 1. Add to `TOOLS.md`
```markdown
- **knowledge-vault**: Store and retrieve knowledge using vector search.
  - **Location:** `{baseDir}/skills/knowledge_vault/SKILL.md`
  - **Command:** `python {baseDir}/skills/knowledge_vault/run.py --action search --query "<QUESTION>"`
```
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The usage example encourages storing sensitive personal data ('prefers spicy food' and 'allergic to peanuts') in long-term memory without any warning about consent, retention, minimization, or deletion. In a memory skill, this is especially risky because the whole purpose is durable storage and retrieval of personal context, which can lead to privacy violations or unnecessary retention of sensitive user data.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
User-provided content is transmitted to Google's embedding API with no in-file disclosure or consent mechanism, which can expose sensitive or proprietary data to a third-party service. In a long-term memory skill, the risk is elevated because users may store highly sensitive notes, and the skill's purpose encourages broad ingestion of data.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The skill can automatically create external TiDB instances by calling a remote provisioning API, which materially expands its capability beyond simple local memory management. In an agent setting, this can create unreviewed outbound network activity, persistent external resources, and storage locations for sensitive data without explicit user approval.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for i in range(3):
        try:
            cmd = ["curl", "-sS", "-X", "POST", api_url, "-H", "content-type: application/json", "-d", "{}"]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode == 0:
                data = json.loads(result.stdout)
                dsn = data.get("instance", {}).get("connectionString")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill persists a DSN containing database credentials in a predictable file under the user's home directory without setting restrictive permissions or notifying the user. Local users, other processes, or backups may be able to recover these credentials and gain unauthorized access to the provisioned database and its stored memory contents.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pymysql
google-genai
Confidence
97% confidence
Finding
The dependency manifest specifies `pymysql` without a version constraint, which makes builds non-reproducible and can silently pull in a vulnerable or breaking release over time. In a security-sensitive memory storage skill that likely connects to a database, dependency drift increases supply-chain risk and makes it impossible to verify whether known-vulnerable versions are avoided.

Unverifiable Dependency: pymysql has 2 known advisory(ies) (CVE-2024-36039 (PyMySQL SQL Injection vulnerability); CVE-2024-36039 (PyMySQL SQL Injection vulnerability)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
98% confidence
Finding
The manifest includes `pymysql` without a version pin even though the package has known advisories, so there is no way to determine from this file whether installation will select a fixed or affected release. Given this skill is a long-term RAG memory store backed by TiDB, a vulnerable database client can be more consequential because it sits on the path to persistent data operations and may enable injection-related compromise depending on how the library is used.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pymysql
google-genai
Confidence
94% confidence
Finding
`google-genai` is also unpinned, so the installed version may vary across environments and over time. That creates supply-chain and stability risk, especially for an agent skill where model SDK behavior changes could affect security boundaries, request handling, or data exposure.

Context-Inappropriate Capability

Low
Confidence
72% confidence
Finding
The code accesses GEMINI_API_KEY and TiDB connection credentials from environment variables to operate. While credentials are practically needed for embeddings and database access, the manifest description does not disclose environment-secret access as part of the skill's scope, so this is an additional capability beyond the stated purpose.