Back to skill

Security audit

OpenClaw Advanced Memory

Security checks for vulnerabilities and agentic risk

Overview

This memory skill is coherent, but it continuously records agent conversations into persistent databases with auto-start background jobs and insufficient privacy and access controls.

Treat this as a Review install. Use it only on a trusted single-user machine or hardened local network, bind Redis and Qdrant to loopback or add authentication, inspect and fix install.sh before running it, add explicit pause/purge/uninstall controls, and avoid enabling it for conversations that may contain secrets, regulated data, or third-party personal information.

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

T02 · Agent Memory Poisoning

Error
Location
scripts/mem_curate.py:82
Finding

Untrusted Transcript Content Can Poison Permanent Agent Memory

Content
View full analysis
list[dict]: """Send transcript to LLM curator and get back gems.""" system_prompt = load_curator_prompt() user_prompt = f"""Here is the full conversation transcript for {date_str}. Read it holistically and extract the valuable gems worth remembering long-term. TRANSCRIPT: {transcript[:30000]} Return ONLY a JSON array of gems. No other text.""" try: resp = requests.post( f"{OLLAMA_HOST}/api/chat", json={ "model": CURATOR_MODEL, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], "stream": False, "options": { "temperature": 0.3, "num_predict": 4096, }, }, timeout=300, ) ``` The generated data is subsequently accepted and stored: ```python gems = json.loads(content) if not isinstance(gems, list): print(f" ⚠️ LLM returned non-list: {type(gems)}", file=sys.stderr) return [] return gems ``` ```python point = PointStruct( id=str(uuid.uuid4()), vector=vector, payload={ "gem": gem_text, "context": context, "date": gem.get("date", date_str), "timestamp": ts_float, "categories": gem.get("categories", []), "project": gem.get("project"), "people": gem.get("people", []), "importance": gem.get("importance", "medium"), "confidence": gem.get("confidence", 0.8), "content_hash": content_hash(gem_text), "curated_at": datetime.now(t ...[truncated 2304 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
README.md:82
Finding

Documented Deployment Exposes Sensitive Redis and Qdrant Services Without Authentication

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install.sh:36
Finding

Sensitive Memory Content Is Written to Predictable Shared Temporary Files

Content
View full analysis
> /tmp/mem-warm.log 2>&1" # mem-curate: daily at 2 AM (9 AM UTC, which is 2 AM MST) CURATE_CRON="0 9 * * * /usr/bin/python3 $SCRIPT_DIR/mem_curate.py >> /tmp/mem-curate.log 2>&1" ``` The curation process logs excerpts from permanent memories: ```python # Print gems for logging for gem in gems: imp = gem.get("importance", "?") cats = ", ".join(gem.get("categories", [])) print(f" [{imp}] [{cats}] {gem.get('gem', '')[:80]}") ``` ### Technical Analysis The cron jobs append output to fixed filenames under `/tmp`. On common multi-user systems, `/tmp` is shared and permits users to create entries. This creates two related risks: 1. **Confidentiality risk:** log files may be created with permissions that allow other local users to read curated memory excerpts. 2. **Symlink risk:** another local user may create a predictable path as a symbolic link before the scheduled process opens it. Shell append redirection follows symbolic links, allowing content to be appended to another file writable by the victim account. The logged gems may contain people information, business decisions, infrastructure changes, customer information, or other sensitive conversation-derived facts. ### Attack Path 1. A local attacker predicts `/tmp/mem-curate.log` or `/tmp/mem-warm.log`. 2. The attacker either waits for the log to be created and attempts to read it, or creates a symbolic link at the expected path. 3. The scheduled cron job opens the predictable path using append redirection. 4. Sensitive curation output is written to the shared file or symlink target. 5. The attacker reads the disc ...[truncated 576 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/install.sh:13
Finding

Installer Retrieves Unpinned Python Dependencies and Documentation Recommends a Mutable Container Image

Content
View full analysis
/dev/null || true ``` The deployment example also uses a mutable image tag: ```yaml services: qdrant: image: qdrant/qdrant:latest ports: - "6333:6333" ``` ### Technical Analysis No exact package versions or integrity hashes are specified. Consequently, the code installed by the same audited script can change over time without any modification to this repository. The `latest` container tag has the same mutability problem: it can resolve to a different image on future deployments. This weakens reproducibility and makes it impossible to establish that installed artifacts match those subjected to security review. There is no evidence in the project that the named packages are currently malicious. The vulnerability is the unsafe supply-chain practice and resulting exposure to upstream compromise, unexpected replacement, or incompatible future releases. The command also suppresses errors and continues through `|| true`, which can leave an installation using missing, stale, or partially upgraded dependencies. ### Attack Path 1. An upstream package account, release process, registry, or distribution channel is compromised, or a future release introduces malicious behavior. 2. A user runs `scripts/install.sh`. 3. `pip3` resolves the newest available versions rather than an audited version set. 4. Package installation or later imports execute the changed code under the installing user's account. 5. Similarly, a future deployment may pull a changed Qdrant image through the `latest` tag. This path depends on compromise or unsafe change in an upstream dependency sourc ...[truncated 613 chars]
Remediation
View remediation
/dev/null || true`; report dependency failures and stop installation cleanly. 7. Add automated dependency vulnerability and provenance scanning. 8. Document an update process that reviews and tests each dependency change before deployment. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/install.sh:4
Finding

Installer Applies Partial Changes Before Failing on a Missing Systemd Unit

Content
View full analysis
/dev/null || true # 2. Create Qdrant collections echo "" echo "🗄️ Setting up Qdrant collections..." python3 "$SCRIPT_DIR/setup_collections.py" # 3. Install systemd service for mem-capture echo "" echo "🔧 Installing mem-capture systemd service..." mkdir -p ~/.config/systemd/user/ cp "$PARENT_DIR/mem-capture.service" ~/.config/systemd/user/ systemctl --user daemon-reload systemctl --user enable mem-capture.service systemctl --user start mem-capture.service ``` The supplied project directory does not contain the referenced root-level `mem-capture.service` file. ### Technical Analysis The installer modifies the Python environment and creates Qdrant collections before verifying that all required installation artifacts exist. Because `set -e` is enabled, the failed `cp` terminates the script after these earlier modifications have occurred. No transactional rollback or uninstall operation is provided. This can leave the system in a partially installed and misleading state. In this exact artifact, the failure also means the subsequent cron registration is not reached during a normal fresh run. This is primarily an installation integrity and reliability weakness rather than an external code-execution primitive. ### Attack Path 1. A user runs the installer from the supplied project. 2. Python package installation is attempted. 3. Qdrant collections are created. 4. The installer attempts to copy the absent `mem-capture.service`. 5. The copy fails, and `set -e` terminates the script. 6. Earlier package and da ...[truncated 690 chars]
Remediation
View remediation
&2 exit 1 } done ``` 3. Add rollback handling for collections, generated files, service units, and cron entries. 4. Provide a documented uninstall script. 5. Report dependency failures instead of suppressing them. 6. Verify service and timer installation at the end and return a nonzero status when installation is incomplete. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (20)

Ssd 3

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The curation rules explicitly state that 'people info' from daily conversations can be preserved in long-term memory, which materially increases privacy risk and the chance of creating durable profiles about individuals. In context, this is more dangerous than generic conversation storage because it encourages selective retention of person-related details that may be sensitive, inaccurate, or unnecessary, and then stores them 'forever.'

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script is explicitly designed to monitor all active OpenClaw session transcript files and persist all non-tool conversation turns into Redis, including user-provided text. In this skill context, that means broad surveillance and secondary storage of potentially sensitive conversational data across sessions, which materially increases exposure, enables cross-session data aggregation, and creates a valuable target for abuse or compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly promotes persistent capture of conversation transcripts and long-term storage of extracted facts, decisions, and people information, but it does not foreground privacy, consent, retention, or sensitivity risks. In an agent-memory skill, this is security-relevant because operators may enable continuous logging of sensitive chats, credentials, personal data, or business information without understanding the surveillance and retention implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The installation section tells users to run an installer script, and only afterward states that it will create a systemd service and cron jobs that persistently monitor transcripts and process data. That omission reduces informed consent for host modifications and persistence mechanisms, which is risky because users may execute the installer without realizing it establishes background services and scheduled tasks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill advertises persistent cross-session memory and long-term storage of extracted conversation content, but it does not present a clear warning, consent flow, or usage caveat to users whose conversations will be captured and retained. This creates a privacy and transparency risk because users may disclose sensitive personal, business, or credential-adjacent information without understanding it will be stored, indexed, and later recalled.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The described design persistently stores conversations and extracts long-term memory items, including decisions and potentially personal information, without describing data minimization, category restrictions, or safeguards against collecting unnecessary sensitive content. In an agent memory context, this is dangerous because normal user interactions often contain names, personal details, internal project data, and secrets that can become durable and searchable artifacts.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

An always-running transcript watcher combined with scheduled flushing and nightly summarization establishes continuous collection of user conversations by default. That increases exposure because sensitive content may be captured passively and retained even when users do not intend a given interaction to become part of a long-term searchable memory system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This prompt explicitly directs the agent to retain long-term memory about personal preferences, relationships, contacts, business events, and infrastructure changes, which can include sensitive personal and operational data. Without any consent, minimization, retention limits, or sensitivity filtering, it creates a privacy and security risk by encouraging durable storage of information that users may not expect to be remembered.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/embeddings.py (reported line 16)May include surrounding context.

python
def get_embedding(text: str) -> list[float]:
    """Get embedding vector for a text string."""
    resp = requests.post(
        f"{OLLAMA_HOST}/api/embeddings",
        json={"model": EMBED_MODEL, "prompt": text},
        timeout=30,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code sends the caller-provided text to an HTTP endpoint for embedding generation via requests.post, which is a network transmission of user or system data. Although the module docstring names the backend, there is no confirmation prompt, logging, or warning in the function docstrings/comments that input text will be sent to a service.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

sh
echo "📦 Installing Python dependencies..."
pip3 install --user qdrant-client redis requests 2>/dev/null || true

# 2. Create Qdrant collections
echo ""
echo "🗄️  Setting up Qdrant collections..."
python3 "$SCRIPT_DIR/setup_collections.py"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The installer makes persistent changes by enabling a user systemd service, installing cron jobs, and creating executable helper scripts, but it does not present a clear warning or request consent for these actions. Hidden persistence is risky in an agent skill because it can continue collecting or processing data after the initial install and may surprise users who expect a local one-time setup.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
97% confidence
Finding

Enabling and starting a user systemd service creates persistent background execution beyond the install session. For an agent skill, this is particularly sensitive because it can continuously run capture logic and survive reboots or user logins, increasing the blast radius if the service or referenced code is later altered.

Content

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

sh
mkdir -p ~/.config/systemd/user/
cp "$PARENT_DIR/mem-capture.service" ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable mem-capture.service
systemctl --user start mem-capture.service
echo "   ✅ mem-capture service installed and started"

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script claims an idempotent cron update, but the pipeline rewrites the user's crontab with only the filtered existing entries plus two new jobs, which can delete unrelated scheduled tasks. This can disrupt backups, security jobs, or other user automation and creates persistence without clearly preserving prior configuration.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
97% confidence
Finding

Installing recurring cron jobs establishes persistence by causing code in this repository to execute automatically every 30 minutes and daily thereafter. In the context of an agent skill, unattended scheduled execution increases risk because any later modification of the referenced scripts will run without further user review.

Content

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

sh
CURATE_CRON="0 9 * * * /usr/bin/python3 $SCRIPT_DIR/mem_curate.py >> /tmp/mem-curate.log 2>&1"

# Add to crontab (idempotent)
(crontab -l 2>/dev/null | grep -v "mem_warm.py" | grep -v "mem_curate.py"; echo "$WARM_CRON"; echo "$CURATE_CRON") | crontab -
echo "   ✅ Cron jobs installed"
echo "      - mem-warm: every 30 minutes"
echo "      - mem-curate: daily at 2 AM MST (9 AM UTC)"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The service continuously captures new conversation turns from session transcripts and pushes them into Redis without any consent check, notice, access control logic, or data-minimization beyond simple noise filtering. Because these transcripts can contain sensitive user and assistant content, this creates a real privacy and data-handling risk if Redis is accessed by other local services, operators, or an attacker.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/mem_curate.py (reported line 99)May include surrounding context.

python
Return ONLY a JSON array of gems. No other text."""

    try:
        resp = requests.post(
            f"{OLLAMA_HOST}/api/chat",
            json={
                "model": CURATOR_MODEL,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code posts the full conversation transcript to an Ollama chat API, which is a network/HTTP transmission of user or system data. While the module docstring says it uses an LLM to read warm memories, there is no user-facing disclosure at the point of transmission about sending transcript contents to the service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The cleanup routine permanently deletes warm memories older than the retention threshold. Although the top-level docstring mentions cleanup, the destructive operation itself has no confirmation gate and no inline warning comment emphasizing that stored data will be removed automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script prints memory search results directly to stdout, including potentially sensitive fields such as people, project, context, channel, and free-text memory content, with no access control, redaction, consent check, or even a privacy warning. In a memory-recall skill, this is more dangerous than generic search because the whole purpose is to retrieve stored historical information, which may contain personal, confidential, or internal project data that an unauthorized or overbroad caller could easily enumerate.

Content

No source excerpt is available for this finding.