Back to skill

Security audit

MeshMorize

Security checks for vulnerabilities and agentic risk

Overview

MeshMorize is a coherent local memory skill, but it asks agents to access transcript databases and rewrite automation payloads without clear consent or scoping.

Review before installing. Use this only if you are comfortable with plaintext local memory, and do not let it access transcript databases or automation registries unless you explicitly approve the exact session, time range, and job being read or changed. Avoid logging secrets or personal data, and clean up any temporary transcript copies.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:93
Finding

Sensitive Transcript Database Access Through Crash-Recovery Instructions

Content
View full analysis
/agents//agent/openclaw-agent.sqlite* /tmp/db-inspect/ ``` The exact path depends on the OpenClaw version and agent layout — look under your host's OpenClaw state directory (commonly `~/.openclaw/`), find the agent's `agent/` folder, and copy every `*.sqlite*` file. The schema is `transcript_events` with `session_id`, `seq`, `created_at`, and an `event_json` payload column. 3. **Convert the wall-clock window to epoch milliseconds** (use the host's timezone; `+0300` in this example): ```bash date -d "YYYY-MM-DD HH:MM:SS +0300" +%s%3N # repeat for start and end ``` 4. **Locate the user messages in the window** (`event_json` holds `{"message":{"role":"user","content":...}}`): ```bash sqlite3 /tmp/db-inspect/openclaw-agent.sqlite \ "SELECT seq, created_at, substr(event_json,1,400) FROM transcript_events \ WHERE session_id='' AND created_at BETWEEN AND \ AND event_json LIKE '%\"role\":\"user\"%' ORDER BY seq;" ``` 5. **Dump the full window and parse it** into readable dialogue: ```bash sqlite3 /tmp/db-inspect/openclaw-agent.sqlite \ "SELECT event_json FROM transcript_events WHERE sessi ...[truncated 2913 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:126
Finding

Unscoped Inspection and Modification of the Host Automation Registry

Content
View full analysis
/1000))"`. 3. **Beware stale relative time.** If the payload says "yesterday"/"today" but the job was created days or weeks ago, it re-fires the same stale text on every run — never relay it as fresh news. Verify against the creation date first. 4. **Rewrite the payload with absolute dates** so future runs stop repeating the stale text. **Rule:** `memory_search` only greps file layers — automation payloads live outside them. An empty search result does not mean there is no record. ``` ### Technical Analysis The Skill treats an empty local-memory search as justification to enumerate and read the host automation registry. It then instructs the agent to rewrite payloads containing relative dates. The procedure does not restrict access to automations created by MeshMorize, require an ownership marker, define a project namespace, or require user confirmation before mutation. A job selected through a heuristic name match may belong to another user, project, agent, or system component. Reading automation payloads can disclose private plans, command arguments, internal paths, or secrets. Rewriting a payload changes persistent scheduled b ...[truncated 1246 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/memory_check.py:30
Finding

PATH Hijacking Through Shell-Based Execution of Unqualified Commands

Content
View full analysis
30}") rc, out, _ = run("auto_log 'memcheck' 'memory compliance check'") if rc == 0: ok("auto_log wrote entry ✅") else: fail(f"auto_log failed ({rc})") # 2. BRIDGE — mem-bridge init results.append(f"\n{'🔗 2. BRIDGE':>30}") rc, out, _ = run("mem-bridge init") if rc == 0: ok("bridge initialized ✅") else: fail(f"bridge init failed: {out[:80]}") # 9. TOOLS PATH results.append(f"\n{'🔧 9. TOOLS ON PATH':>30}") tools = {"auto_log": "auto_log", "memory_search": "memory_search", "mem-bridge": "mem-bridge"} all_found = True for name, cmd in tools.items(): rc, out, _ = run(f"which {cmd}") if rc == 0: ok(f"{name} → {out}") else: fail(f"{name} not on PATH!") all_found = False ``` ### Technical Analysis The `run` helper passes command strings to `subprocess.run` with `shell=True`. The compliance check then invokes `auto_log`, `mem-bridge`, and `which` by unqualified name. The shell resolves these names according to the invoking process's `PATH`. If an attacker can place a malicious executable in an earlier writable directory, running `memcheck` executes that file with the privileges of the user or agent. The check that reports tool locations occurs only after `auto_log` and `mem-bridge` have already been executed, so it cannot prevent the hijack. The current command strings are internally fixed, so direct user-input command injection was not identified in the audited version. The confirmed weakne ...[truncated 1179 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (48)

Ssd 3

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The crash-gap recovery workflow instructs operators to extract transcript events from the agent transcript database and feed them back verbatim. That increases risk beyond normal logging because it encourages bulk recovery and reprocessing of historical conversation data, including potentially sensitive or deleted user content, which can amplify disclosure, unauthorized reuse, and privacy violations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The code substantially overlaps with the declared memory-system theme: it is local-first, file-based, survives restarts via checkpoint files, logs entries, maintains a mesh graph, and has fresh-layer/session-wrap functionality. However, several specifically declared capabilities are absent. There is no grep or search functionality across layers, no compliance-check logic, no automation-registry lookup, and no transcript-based crash-gap recovery. The 'search before answering, log after answering' behavior is described but not implemented or enforced in this script. Additionally, while a constant says ROTATION_LEVELS = 5, the actual rotate() logic only handles today/yesterday/2-days-ago, so the claimed 5-day rotation is not truly implemented. These are material gaps between description and actual behavior, so this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description is for a full memory system with specific runtime behaviors and data-management capabilities. The supplied code chunk does not implement that system; instead, it performs a diagnostic/compliance audit of whether supporting files and commands exist and whether certain initialization steps succeed. While 'compliance check' is one item mentioned in the description, this chunk's primary purpose is health checking, not memory management. It also touches resources not clearly declared, such as a secrets directory, PATH inspection, and heartbeat/core identity files. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The recovery guidance explicitly instructs extracting missing conversations from transcript storage and replaying recovered user words verbatim. That creates a strong risk of resurfacing sensitive prior inputs to the wrong context or user and of persisting raw confidential text beyond its original scope.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
96% confidence
Finding

This is a concrete tool-parameter abuse risk because the wrapper centralizes shell execution and is used to invoke tools by bare command name, making execution dependent on the ambient shell and PATH. On OpenClaw-like hosts where agent skills may run unattended, a malicious or compromised PATH entry could cause attacker-controlled binaries or shell behavior to run instead of the intended tools.

Content

Scanner excerpt · scripts/memory_check.py (reported line 32)May include surrounding context.

python
def run(cmd, timeout=10):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
        return r.returncode, r.stdout.strip(), r.stderr.strip()
    except Exception as e:
        return -1, "", str(e)

Ssd 3

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly promotes persistent, plaintext storage of conversational memory and states that every exchange should be logged. Even without malicious intent, this creates a real confidentiality risk because user-supplied secrets, personal data, or internal business information can be captured and retained indefinitely in local files, increasing exposure through compromise, backup leakage, or accidental repo inclusion.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README's 'Log every exchange' protocol operationalizes indiscriminate persistence of conversation content, which is a concrete data retention vulnerability in a memory tool. Because the logs are plain Markdown files intended to survive crashes and reinstalls, any sensitive prompts, credentials, regulated data, or confidential discussions may be stored long-term and later disclosed to other tools, users, or attackers with filesystem access.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill instructs use of shell, environment-derived paths, and broad file read/write behavior, but it does not declare any tool scope or permission constraints. That increases the blast radius because a host may grant more capability than the memory workflow actually needs, making accidental or unsafe file/system access easier.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The skill description is broad enough that an agent may invoke it in many conversational contexts, including ones where persistent logging or host-state inspection is unnecessary. Overbroad activation increases the chance that sensitive conversations get searched, logged, or persisted by default.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill's core workflow promotes durable retention of broad conversational material across daily logs, rolling logs, checkpoints, and recovery paths. Persistent natural-language storage increases the likelihood of accidental retention of secrets, personal data, or confidential project details that may later be exposed through search, backup, or file sharing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The protocol directs routine logging of exchanges to persistent files without a just-in-time warning or consent checkpoint, even though the content may include preferences, plans, corrections, or sensitive context. This creates a privacy risk because users may not expect durable storage of conversational content in local logs.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The 'log every exchange' guidance semantically encourages the agent to persist user-provided content whenever it seems potentially useful later. That can capture more data than necessary and makes leakage through local files, backups, grep search, or later summaries more likely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The crash-gap recovery workflow directs the agent/operator to inspect copied SQLite transcript databases outside the stated local memory files, exposing raw historical conversation data and adjacent host state. This expands access from intended memory files into broader transcript storage, which can contain sensitive user inputs and system metadata not needed for normal operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The transcript-recovery section explains how to extract and parse local SQLite transcript stores but does not require an explicit warning or consent step at the point of access. Because transcript databases can contain sensitive historical conversations, this omission materially raises privacy and unauthorized-disclosure risk.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The instructions create additional copies of agent transcript databases under /tmp/db-inspect, extending the lifetime and accessibility of sensitive session data beyond the original store. Temporary directories may have weaker handling controls, and duplicated transcript files increase exposure to local users, backups, or later accidental reuse.

Content

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

  1. Identify the session that was live at the time. Session listings show a sessionId per sessionKey (for the main chat this is your agent's main session key).
  2. Copy the database first — sqlite3 refuses to open the live DB while the gateway holds it:
    bash
    mkdir -p /tmp/db-inspect
    cp <openclaw-state>/agents/<agent-id>/agent/openclaw-agent.sqlite* /tmp/db-inspect/
    
    The exact path depends on the OpenClaw version and agent layout — look under your host's OpenClaw state directory (commonly ~/.openclaw/), find the agent's agent/ folder, and copy every *.sqlite* file. The schema is transcript_events with session_id, seq, created_at, and an event_json payload column.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The automation-registry lookup instructs the agent to inspect host-side scheduler or registry state beyond the declared file-memory boundaries. That broadens data access to external operational state that may contain unrelated tasks, payloads, timestamps, or sensitive reminders, creating unnecessary exposure.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

Persistent session memory is the skill's purpose, but retaining every exchange and related state across restarts creates real privacy and data-retention risk if users are not clearly informed and protected. In this context, persistence is more dangerous because other functions automatically log, summarize, and replay content, compounding exposure across files and sessions.

Content

Scanner excerpt · memory/bridge.py (reported line 12)May include surrounding context.

python
- Session wrapping

Usage:
  bridge.py init          ← session start (rotate + create today)
  bridge.py daily         ← daily rotation only
  bridge.py log <msg>     ← append timestamped entry to today's log
  bridge.py decision <topic> <body>   ← save a decision file

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file fixes the timezone/locale context to Europe/Athens and describes timestamps as Athens time, which imposes a specific locale behavior on all users. The policy allows locale constraints only when users are given a choice or when the restriction is clearly documented as justified for a region-specific tool, neither of which is present here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a fresh daily layer with a 5-day rotation, and the code even sets ROTATION_LEVELS to 5. However, the actual rotate() implementation only copies today.md to yesterday.md and yesterday.md to 2-days-ago.md, with no handling for days 3-5. This is a direct mismatch between the advertised memory retention behavior and implemented behavior.

Content

No source excerpt is available for this finding.

Tainted flow: 'yesterday_path' from os.environ.get (line 54, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 70)May include surrounding context.

python
print("🔄 Rotating fresh files...")
    if os.path.exists(yesterday_path):
        shutil.copy2(yesterday_path, two_days_path)
    shutil.copy2(today_path, yesterday_path)
    return True

Tainted flow: 'today_path' from os.environ.get (line 511, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 71)May include surrounding context.

python
print("🔄 Rotating fresh files...")
    if os.path.exists(yesterday_path):
        shutil.copy2(yesterday_path, two_days_path)
    shutil.copy2(today_path, yesterday_path)
    return True

def create_today():

Tainted flow: 'path' from os.environ.get (line 194, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 93)May include surrounding context.

python
(see projects in workspace/ for details)
"""
    path = os.path.join(FRESH, "today.md")
    with open(path, 'w') as f:
        f.write(template)
    print(f"📝 Created fresh/today.md ({today})")

Tainted flow: 'path' from os.environ.get (line 194, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 168)May include surrounding context.

python
(see projects in workspace/ for details)
"""
    path = os.path.join(FRESH, "today.md")
    with open(path, 'w') as f:
        f.write(template)
    print(f"📝 Created fresh/today.md ({today})")

Tainted flow: 'path' from os.environ.get (line 194, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 177)May include surrounding context.

python
(see projects in workspace/ for details)
"""
    path = os.path.join(FRESH, "today.md")
    with open(path, 'w') as f:
        f.write(template)
    print(f"📝 Created fresh/today.md ({today})")

Tainted flow: 'path' from os.environ.get (line 194, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · memory/bridge.py (reported line 356)May include surrounding context.

python
(see projects in workspace/ for details)
"""
    path = os.path.join(FRESH, "today.md")
    with open(path, 'w') as f:
        f.write(template)
    print(f"📝 Created fresh/today.md ({today})")

Static analysis

No suspicious patterns detected.