Back to skill

Security audit

pg-memory

Security checks for vulnerabilities and agentic risk

Overview

This skill is a legitimate PostgreSQL memory system, but it handles sensitive cross-session agent history with several overbroad and unsafe database, credential, and restore behaviors that require review before installation.

Install only if you are comfortable administering PostgreSQL for sensitive agent memory. Use a dedicated least-privilege database role, restrict network access to trusted hosts or a VPN, require TLS for remote PostgreSQL, chmod credential files to 600, avoid the --reset/restore --drop paths unless you have verified backups, and do not enable shared multi-agent use until session scoping is fixed and tested.

Vulnerability Patterns
  • 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
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/memory_handler.py:211
Finding

Cross-Session Disclosure of Stored Agent Memory

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_memory.py:2459
Finding

Shell Command Injection in Database Backup and Restore

Content
View full analysis
{backup_path}" result = subprocess.run(cmd_str, shell=True, capture_output=True, text=True) else: # Run pg_dump and redirect to file with open(backup_path, 'w') as f: result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True) ``` ```python if is_compressed: cmd_str = f"gunzip -c {backup_path} | psql -h {db_host} -p {db_port} -U {db_user} -d {db_name}" result = subprocess.run(cmd_str, shell=True, capture_output=True, text=True) else: cmd = [ "psql", "-h", db_host, "-p", str(db_port), "-U", db_user, "-d", db_name, "-f", str(backup_path) ] result = subprocess.run(cmd, capture_output=True, text=True) ``` ### Technical Analysis The compressed backup and restore branches construct shell command strings by interpolating path and database configuration values, then execute those strings using `shell=True`. Values such as `backup_path`, `db_host`, `db_user`, and `db_name` are not safely shell-quoted. If an attacker can influence an output directory, backup filename, restore path, environment variable, or configuration file, shell metacharacters can terminate or extend the intended command. The safe argument-array behavior used in the uncompressed branches is lost when the code invokes a shell to implement pipelines and redirection. ### Attack Path 1. An attacker gains influence over `output_dir`, `backup_file`, or a PostgreSQL setting loaded from environment or `config.env`. 2. The attacker supplies a value containing shell syntax. 3. A user or automated process invokes compressed `backup()` or restores a `.gz` backup. 4. The value is inter ...[truncated 727 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
client-setup.sh:184
Finding

Plaintext Database Credential File Created Without Enforced Restrictive Permissions

Content
View full analysis
"$CONFIG_DIR/config.env" << EOF # pg-memory Configuration # Generated: $(date -Iseconds) # Database Connection PG_MEMORY_HOST=$DB_HOST PG_MEMORY_PORT=$DB_PORT PG_MEMORY_DB=$DB_NAME PG_MEMORY_USER=$DB_USER PG_MEMORY_PASSWORD=$DB_PASSWORD # Agent Identity OPENCLAW_NAME=$AGENT_NAME # Performance PG_MEMORY_POOL_MIN=2 PG_MEMORY_POOL_MAX=10 PG_MEMORY_TIMEOUT=30 EOF echo "✓ Configuration saved to: $CONFIG_DIR/config.env" ``` ### Technical Analysis The setup script stores the database password in plaintext but does not set a restrictive umask before creating the file and does not apply mode `0600` afterward. The resulting permissions depend on the invoking user's environment. With a common `022` umask, the file may be readable by other local accounts. The documentation recommends `chmod 600`, but the installer does not enforce that control. The unquoted here-document also performs shell expansion while generating the file. Passwords containing expansion-sensitive characters may be changed or handled unexpectedly. ### Attack Path 1. A user runs `client-setup.sh` and enters credentials for the shared memory database. 2. The script writes the password to `config.env`. 3. The file inherits permissions from the current umask. 4. Another local user or compromised process reads the configuration file. 5. The attacker uses the recovered credentials to connect to the PostgreSQL server. 6. The attacker reads, modifies, or deletes memory records within the database role's permissions. ### Impact Assessment Exposure of this credential can grant access to a database containing complete conversations, tool parameters and results, user identifiers, observations, and potentially assistant reasoning. In a shared multi-agent installation, one stolen client ...[truncated 224 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
server-setup.sh:152
Finding

SQL Injection During Privileged Database Setup and Excessive CREATEDB Grant

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
server-setup.sh:205
Finding

Unsafe Remote PostgreSQL Exposure Guidance Without Enforced TLS Verification

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
install.sh:111
Finding

Unpinned Third-Party Dependency Installed at Runtime

Content
View full analysis
/dev/null || pip3 install psycopg2-binary print_success "Python dependencies installed" ``` ```bash # Install psycopg2 echo "" echo "Installing psycopg2-binary..." $PYTHON -m pip install psycopg2-binary --quiet echo "✓ psycopg2-binary installed" ``` ### Technical Analysis Both installation paths retrieve and install the latest available `psycopg2-binary` package from the active pip index. No reviewed version, package hash, lockfile, or index restriction is enforced. The installed artifact is subsequently imported by the Skill and therefore executes in the agent's Python process. The exact code installed can change over time without any change to the audited project. The package name appears legitimate rather than typosquatted, so this is an unsafe dependency-management issue rather than evidence that the current dependency is malicious. ### Attack Path 1. A user runs the installer or client setup script. 2. Pip resolves `psycopg2-binary` using the user's configured package index and current latest release. 3. A compromised index, altered pip configuration, compromised future release, or maliciously substituted artifact is selected. 4. Pip installs the package into the user or active Python environment. 5. pg-memory imports the installed package. 6. Malicious package code executes with the privileges and data access of the OpenClaw process. ### Impact Assessment A compromised dependency could execute arbitrary Python or native code, access database credentials, read stored conversation memory, modify agent files, and communicate over the network using the permissions of the installing or running accoun ...[truncated 164 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (116)

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill exposes full database restore capability and optionally drops and recreates the database first. In an agent-accessible component, this is highly dangerous because a bad prompt, misuse, or compromised caller could irreversibly destroy or overwrite all stored data.

Content

No source excerpt is available for this finding.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · MIGRATION.md (reported line 64)May include surrounding context.

sudo -u postgres psql -d openclaw_memory < /tmp/migration_*.sql

Or if compressed:

gunzip -c /tmp/migration_*.sql.gz | sudo -u postgres psql -d openclaw_memory

text

### Step 3: Reconfigure Client

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · server-setup.sh (reported line 87)May include surrounding context.

sh
sudo -u postgres psql -d openclaw_memory < /tmp/migration_*.sql

# Or if compressed:
gunzip -c /tmp/migration_*.sql.gz | sudo -u postgres psql -d openclaw_memory
```

### Step 3: Reconfigure Client

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The troubleshooting guidance tells users to set listen_addresses = '*' and allow host all all 0.0.0.0/0 md5, which can expose PostgreSQL to the entire internet or local network if copied verbatim. Even though a later checklist says not to use 0.0.0.0/0, placing this as troubleshooting advice creates a strong insecure-default pattern that could lead to unauthorized access or brute-force attempts against the database.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The description presents a feature-rich structured memory system, but the provided code chunk is only an installer/bootstrap script. Its actual actions are limited to environment checks, package installation, PostgreSQL connectivity/user/database setup, schema initialization, optional destructive reset, CLI chmod, and config generation. While these setup tasks are consistent with supporting a PostgreSQL-backed memory system, the chunk does not evidence several prominent declared features such as compaction hooks, dual-write, markdown backup, context preservation logic, or multi-agent behavior. Because the declared purpose emphasizes runtime capabilities that are not represented here, and the chunk’s primary purpose is installation rather than the described memory functionality, this is a description/behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents the skill as a structured PostgreSQL memory system with compaction hooks, dual-write behavior, markdown backup, and context preservation for agents. The supplied code chunk does not implement those storage or lifecycle functions. Instead, it adds a separate natural-language querying feature: it constructs prompts, calls a local Ollama model through subprocess, extracts and sanitizes generated SQL, and runs SELECT queries on the pg-memory database. This is materially different from the declared primary purpose and introduces an undeclared capability (LLM-backed NL-to-SQL query execution). While it is related to the broader pg-memory ecosystem, this specific code chunk is not accurately represented by the supplied description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code generally matches the broad claim of being a PostgreSQL-based structured memory system with markdown export/backup behavior and multi-instance/multi-agent support. However, the description omits several substantial capabilities present in the code: natural-language querying (including optional LLM-assisted SQL generation via Ollama), backup/restore through external database tools, JSON import/export, markdown bulk import, reminder and chain management, template support, conflict tracking, and auto-creation of project/task observations. More importantly, some specifically declared features are not supported by the supplied chunk: there is no clear implementation of pre/post-compaction integration, no demonstrated dual-write mechanism, and no concrete full-context-preservation subsystem beyond general storage/export features. Because both undeclared significant capabilities and unsubstantiated declared features are present, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a general-purpose PostgreSQL structured memory system emphasizing full context preservation, dual-write behavior, markdown backup, and compaction integration. The supplied code chunk instead implements a standalone pruning/cleanup script for an existing PostgreSQL memory database. Its primary behavior is retention enforcement: selecting old rows from raw_exchanges, tool_executions, and sessions; archiving some records to compressed JSONL files under a filesystem path; soft-deleting/hard-deleting data; running VACUUM ANALYZE; showing stats; and printing partitioning SQL. Those are materially different capabilities from the declared purpose. Most notably, the code deletes old memory and therefore conflicts with 'full context preservation,' and it does not show dual-write, markdown backup, or compaction integration.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broad agent memory subsystem with specialized memory features, but the supplied code chunk is narrowly focused on operational database partition management. Its primary purpose is maintaining monthly PostgreSQL partitions for raw_exchanges, including creating future partitions and archiving old ones to compressed JSONL before deleting the detached table. This is materially different from a structured memory system and introduces undeclared capabilities, including filesystem archival and destructive schema/data maintenance actions. While it imports AgentMemory for database connectivity, that appears to be a supporting dependency rather than evidence that this chunk implements the declared memory functionality. Therefore, the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a full PostgreSQL-backed memory system with pre/post-compaction integration, dual-write support, markdown backup, and multi-agent context preservation. The supplied code chunk does not implement that system; it is a narrow operational script for regenerating embeddings on existing observations. It accesses PostgreSQL and an Ollama HTTP API, selects records needing embeddings, generates new vectors, and writes them back. None of the headline features in the description—dual-write, markdown backup, compaction integration, or multi-agent orchestration—are evidenced here. While embedding maintenance could be related to a memory system, this chunk’s actual purpose is materially narrower and includes an undeclared external capability (embedding generation via Ollama).

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The explicit rm -rf /opt/homebrew/var/postgresql@16 instruction is a concrete high-risk deletion primitive. Because the skill also implies shell-based setup and maintenance, this materially increases the chance of unsafe execution and permanent loss of the agent's stored history and database state.

Content

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

cat /opt/homebrew/var/log/postgresql@16.log

Re-initialize (WARNING: loses data!)

rm -rf /opt/homebrew/var/postgresql@16 initdb --locale=en_US.UTF-8 -E UTF8 /opt/homebrew/var/postgresql@16

text

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The explicit rm -rf /opt/homebrew/var/postgresql@16 instruction is a concrete high-risk deletion primitive. Because the skill also implies shell-based setup and maintenance, this materially increases the chance of unsafe execution and permanent loss of the agent's stored history and database state.

Content

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

cat /opt/homebrew/var/log/postgresql@16.log

Re-initialize (WARNING: loses data!)

rm -rf /opt/homebrew/var/postgresql@16 initdb --locale=en_US.UTF-8 -E UTF8 /opt/homebrew/var/postgresql@16

text

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

When connection testing fails, the installer proceeds to attempt creation of a PostgreSQL superuser without a clear warning or consent gate. Automatically escalating database privileges is dangerous because it can alter shared local database security posture and create a highly privileged account tied to an application user.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The installer attempts to run createuser -s "$DB_USER", which grants PostgreSQL superuser privileges to the configured database user. For a memory-storage skill, this is unnecessary and materially increases blast radius: compromise of the application or that DB user would enable unrestricted database-level actions across the PostgreSQL instance.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code sends arbitrary natural-language input and the full database schema to an external LLM process, then executes the model-generated SQL directly against the database. Although it tries to restrict queries to SELECT and block obvious write operations, this is still dangerous because an LLM can generate expensive, data-exfiltrating, or side-effecting read queries, and the guardrails are based on brittle string filtering rather than robust query allowlisting or SQL parsing.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

A structured memory skill would reasonably query PostgreSQL, but spawning subprocesses to run 'ollama list' is not an obvious requirement of memory storage or markdown backup. This adds host-level command execution capability unrelated to the manifest's stated core purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill expands beyond memory storage into backup and restore of the whole PostgreSQL database, including filesystem writes and invocation of administrative tools. In an agent skill context, this significantly broadens capability and blast radius, making accidental misuse, data exfiltration, or destructive operations more likely.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a classic tool-parameter abuse issue: attacker-influenced values are embedded into a shell command and executed with shell=True. In a skill that may receive parameters from an LLM-driven workflow, that context materially increases exploitability and risk of arbitrary command execution.

Content

Scanner excerpt · scripts/pg_memory.py (reported line 2460)May include surrounding context.

python
# Add compression if requested
    if compress:
        cmd_str = " ".join(cmd) + f" | gzip > {backup_path}"
        result = subprocess.run(cmd_str, shell=True, capture_output=True, text=True)
    else:
        # Run pg_dump and redirect to file
        with open(backup_path, 'w') as f:

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The restore path combines shell execution with attacker-influenced parameters and a highly privileged operation. This creates a compound risk: arbitrary command execution plus potential full database destruction or overwrite, making it especially severe in an agent-integrated skill.

Content

Scanner excerpt · scripts/pg_memory.py (reported line 2543)May include surrounding context.

python
if is_compressed:
        cmd_str = f"gunzip -c {backup_path} | psql -h {db_host} -p {db_port} -U {db_user} -d {db_name}"
        result = subprocess.run(cmd_str, shell=True, capture_output=True, text=True)
    else:
        cmd = [
            "psql",

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 39)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 42)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 43)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 44)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 47)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · MIGRATION.md (reported line 61)May include surrounding context.

md
# (On Synology: Package Center → PostgreSQL)

# Create database
sudo -u postgres createdb openclaw_memory

# Enable extensions
sudo -u postgres psql -d openclaw_memory -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"