Back to skill

Security audit

Graph-RAG Memory

Security checks for vulnerabilities and agentic risk

Overview

This memory skill is review-worthy because it can persist and index workspace data while its installer automatically runs a background watcher and mutable workspace scripts without enough scoping or user control.

Review this carefully before installing. Use only in a test workspace unless you have inspected the referenced memory-upgrade implementation files, understand what will be ingested into FalkorDB, and are comfortable with a background watcher. Prefer running with --dry-run and --skip-seed first, and do not enable the daemon or recurring refresh until dependency pinning, workspace scoping, config backup, and stop/uninstall controls are added.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (5)

T06 · System Persistence

Error
Location
scripts/install.sh:316
Finding

Installer Enables Persistent Background Execution

Content
View full analysis
> "$LOGFILE" 2>&1 & ``` ```c /* scripts/memwatchd.c:181-186 */ if (g_pending) { time_t now = time(NULL); if (now - g_last_trigger >= DEBOUNCE_SECS) { g_pending = 0; run_refresh(workspace); } } ``` The invoked refresh operation executes the workspace script as follows: ```c /* scripts/memwatchd.c:73-106 */ static void run_refresh(const char *workspace) { char script[PATH_MAX]; snprintf(script, sizeof(script), "%s/memory-upgrade/graph_refresh.py", workspace); /* Check script exists */ struct stat st; if (stat(script, &st) != 0) { fprintf(stderr, "[memwatchd] refresh script not found: %s\n", script); return; } pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "[memwatchd] fork failed: %s\n", strerror(errno)); return; } if (pid == 0) { /* Child: redirect stdout/stderr to /dev/null for quiet operation */ int devnull = open("/dev/null", O_WRONLY); if (devnull >= 0) { dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); } /* Find python3 */ char *python = "/home/node/.local/bin/python3"; struct stat ps; if (stat(python, &ps) != 0) { python = "/usr/bin/python3"; } execl(python, "python3", script, "--quiet", (char *)NULL); _ ...[truncated 2202 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:214
Finding

Workspace Path Injection into Generated Python Code

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/memwatchd.c:30
Finding

Symlink-Unsafe Predictable Files in Shared Temporary Directory

Content
View full analysis
/dev/null; then echo "[memwatchd] Already running (pid $PID)" exit 0 fi fi # Start daemon "$DAEMON" "$WORKSPACE" >> "$LOGFILE" 2>&1 & ``` ### Technical Analysis Both the PID file and log file use fixed names in the globally writable `/tmp` directory. The daemon opens the PID path with `fopen(..., "w")`, and the shell opens the log through append redirection. Neither operation verifies file ownership or type, prevents symlink traversal, or uses exclusive secure creation. A local attacker can pre-create either path as a symbolic link. When a more privileged user starts the daemon, the process follows the link and writes to the attacker-selected target. The PID file also acts as an untrusted process-control record: an attacker can populate it with the PID of an unrelated liv ...[truncated 1494 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/install.sh:143
Finding

Unverified Bootstrap Script and Unpinned Python Dependencies

Content
View full analysis
/dev/null; then if ! command -v pip3 &>/dev/null; then run curl -sS https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py run python3 /tmp/get-pip.py --user --break-system-packages --quiet fi run pip3 install --user --break-system-packages --quiet \ graphiti-core falkordb sentence-transformers httpx log " ✅ Packages installed" else ``` Equivalent unverified setup instructions also appear in `SKILL.md:56-60` and `references/setup.md:21-25`. ### Technical Analysis The installer downloads the current `get-pip.py` from a remote URL and immediately executes it without checking a pinned cryptographic digest or signature. The effective bootstrap payload can therefore change after this Skill has been reviewed. The subsequent `pip3 install` specifies package names but no versions or hashes. Future releases, compromised upstream accounts, dependency confusion in transitive dependencies, or repository compromise can alter the executed installation content. Python package installation may execute build backends or other package-controlled code. The use of `--break-system-packages` bypasses distribution protections and increases the chance that installed packages modify or conflict with the user's managed Python environment. ### Attack Path 1. The user runs the installer on a system where `graphiti_core` or `pip3` is absent. 2. The installer downloads the current remote `get-pip.py`. 3. No digest or signature is compared against an audited value. 4. Python executes the downloaded script. 5 ...[truncated 645 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:261
Finding

Execution and Import of Mutable Code Outside the Audited Package

Content
View full analysis
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description is about a Graph-RAG long-term memory system with temporal knowledge graph, database, embeddings, and query/ingest capabilities. The supplied code chunk does not implement or expose those memory features. Instead, it is an operational startup script for a daemon called memwatchd: it rebuilds a binary if absent, checks whether it is already running via a PID file, and starts it in the background with logging. While this could be a supporting component of a larger memory system, this specific chunk’s actual behavior is daemon build/start supervision, which is materially different from the declared primary purpose and introduces undeclared capabilities such as compiling and launching a background process.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill content includes commands and code that read/write files, access network services, install packages, and invoke shell operations, but the skill declares no explicit tool scope or permissions. This creates a trust and review gap: an agent or operator may invoke a capability-rich skill without clear up-front boundaries on what resources it is expected to touch.

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 supports ingesting conversations, documents, notes, and workspace memory into a persistent graph, but it does not present a clear warning about retention, scope, or privacy consequences. In a memory skill, this context makes the issue more dangerous because users may not realize that sensitive content can be stored long-term and later retrieved or searched.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases include generic terms like 'memory system', 'persistent memory', 'query memory', and especially 'what do you remember', which are likely to appear in ordinary conversation. Overbroad activation can cause the skill to run unexpectedly in contexts involving sensitive user data, increasing the chance of unintended persistence, retrieval, or side effects.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The setup instructions download and execute get-pip.py directly from the internet, then install packages into the environment with --break-system-packages. Executing a remotely fetched bootstrap script is a classic supply-chain risk: if the transport, source, or host is compromised, arbitrary code runs in the user's environment.

Content

Scanner excerpt · references/setup.md (reported line 23)May include surrounding context.

The container's /home/node/.local layer is ephemeral — reinstall after restart:

bash
export PATH=$PATH:/home/node/.local/bin
curl -sS https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py
python3 /tmp/get-pip.py --user --break-system-packages
pip3 install --user --break-system-packages graphiti-core falkordb sentence-transformers

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding

The Docker command references falkordb/falkordb without a version tag or immutable digest, so future pulls may retrieve a changed or compromised image unexpectedly. In setup documentation for persistent memory infrastructure, this creates supply-chain risk and undermines reproducibility of the deployment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

If pip3 is missing, the installer downloads and executes get-pip.py directly from the network, then installs Python packages without any integrity verification, pinning, or user confirmation. This creates a supply-chain risk: a compromised transport path, upstream artifact, or package dependency could result in arbitrary code execution under the user's account during installation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script automatically edits ~/.openclaw/openclaw.json, adding skill loading paths and memory search paths, without explicit consent or backup. Silent modification of user configuration can expand the trust boundary, persist new behavior across restarts, and unexpectedly load additional code or data into the agent environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The installer launches phase3_ingest.py and phase6_full_ingest.py to seed and fully ingest workspace memory content without a clear privacy warning or opt-in gate. In the context of a persistent memory skill, this can exfiltrate or index sensitive workspace contents into long-term storage systems and make them queryable later, increasing confidentiality and retention risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The installer starts a background daemon (memwatchd) against the workspace automatically, without an explicit warning that continuous monitoring will begin. Persistent file-watching changes the system's runtime behavior, can capture newly created sensitive content, and may continue operating after the user believes installation is complete.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The code launches a persistent local daemon and automatically executes a Python script whenever watched markdown files change, creating an ambient execution path tied to file writes. In a memory skill context, this increases attack surface because any actor able to modify watched files in the workspace can repeatedly trigger subprocess execution, potentially causing unauthorized persistence, resource exhaustion, or abuse of the downstream Python refresh pipeline if that script has weaker input handling.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The manifest describes a Graph-RAG memory system for querying, ingesting, status checks, and integration, but this file implements a background Linux inotify daemon that watches markdown files and automatically launches a refresh script. While related to memory ingestion, the autonomous file-watching daemon behavior is a broader operational capability not described in the manifest text.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.