Back to skill

Security audit

Total Recall

Security checks for vulnerabilities and agentic risk

Overview

This memory skill is coherent in purpose, but it needs review because it persistently monitors private transcripts, sends them to LLM endpoints, and includes unsafe shell and file operations.

Install only if you are comfortable with a background memory system reading OpenClaw transcripts and sending summaries to your configured LLM provider. Prefer a trusted HTTPS or local endpoint, review watcher and cron persistence before enabling them, and avoid workspaces with sensitive .env contents until the dotenv parsing, Dream Cycle path handling, and rollback behavior are fixed.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/observer-agent.sh:35
Finding

Unsafe Shell Execution Through Workspace .env Loading

Content
View full analysis
/dev/null)" || true set +a fi ``` The same unsafe `eval` pattern appears in setup, watcher, reflector, and backfill scripts. From `scripts/dream-cycle.sh`: ```bash # Load environment if present if [ -f "$OPENCLAW_WORKSPACE/.env" ]; then set -a # shellcheck disable=SC1090 source "$OPENCLAW_WORKSPACE/.env" set +a fi ``` ### Technical Analysis The scripts treat `.env` as executable shell code rather than as a data file. Restricting the variable names with `grep` does not neutralize shell syntax in the corresponding values. For example, a matching assignment can contain command substitution: ```bash LLM_MODEL=$(malicious-command) ``` When passed to `eval`, the command substitution is executed. Quoting, semicolons, redirections, and other shell constructs can similarly alter execution. The Dream Cycle implementation is broader because it directly sources the entire `.env` file. Any shell statement in that file executes under the account running the scheduled Dream Cycle. This issue is particularly significant because observer and Dream Cycle operations are intended to run through persistent services or scheduled jobs. A malicious `.env` modification can therefore result in delayed and recurring command execution. ### Attack Path 1. An attacker, compromise ...[truncated 956 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Error
Location
scripts/session-recovery.sh:62
Finding

Persistent Agent Memory Poisoning Through Untrusted Transcript Content

Content
View full analysis
/dev/null | jq -r --arg cutoff "$CUTOFF_ISO" ' select(.timestamp != null and (.timestamp > $cutoff)) | select(.message.role == "user" or .message.role == "assistant") | .message as $m | (if $m.role == "user" then "USER" else "ASSISTANT" end) as $who | ( if ($m.content | type) == "array" then [$m.content[] | select(.type == "text") | .text] | join(" ") elif ($m.content | type) == "string" then $m.content else "" end ) as $text | select($text != "" and ($text | length) > 5) | "[\($time)] \($who): \($text[0:500])" ' ``` It passes that content to an LLM and appends the returned text to persistent memory: ```bash PAYLOAD=$(jq -n \ --arg system "$SYSTEM_PROMPT" \ --arg messages "Today is $TODAY. Compress these recent messages into observations:\n\n$RECENT_MESSAGES$DEDUP_CONTEXT" \ '{ model: "placeholder", messages: [ {role: "system", content: $system}, {role: "user", content: $messages} ], max_tokens: 2000, temperature: 0.3 }') ``` ```bash if grep -q "^Date: $TODAY" "$OBSERVATIONS_FILE"; then echo "" >> "$OBSERVATIONS_FILE" echo "$OBSERVATION" | sed "/^Date: $TODAY$/d" >> "$OBSERVATIONS_FILE" else echo "" >> "$OBSERVATIONS_FILE" echo "$OBSERVATION" >> "$OBSERVATIONS_FILE" fi ``` If observer recovery fails, raw transcript content is written directly: ```bash if [ -n "$RECENT_MESSAGES" ]; then echo "" >> "$OBSERVATIONS_FILE" echo "" >> "$OBSERVATIONS_FILE" echo "$RECENT_MESSAGES" >> "$OBSERVA ...[truncated 2226 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/observer-agent.sh:203
Finding

Unrestricted Transmission of Conversation Transcripts and Persistent Memory

Content
View full analysis
/dev/null | head -10) ``` ```bash RECENT_MESSAGES=$(cat "$TMPMSGS" | grep -v "^$" | head -150 || true) ``` It sends those excerpts, along with existing memory context, to a configurable endpoint: ```bash RESPONSE=$(curl -s --max-time 60 "$LLM_BASE_URL/chat/completions" \ -H "Authorization: Bearer $LLM_API_KEY" \ -H "Content-Type: application/json" \ -d "$ATTEMPT_PAYLOAD") log "DEBUG: LLM Response (first 500 chars): ${RESPONSE:0:500}" ``` The reflector transmits the complete observations file: ```bash CURRENT_OBS=$(cat "$OBSERVATIONS_FILE") SYSTEM_PROMPT=$(cat "$REFLECTOR_PROMPT") TODAY=$(date '+%Y-%m-%d') PAYLOAD=$(jq -n \ --arg system "$SYSTEM_PROMPT" \ --arg obs "Today is $TODAY. Here is the current observation log to consolidate:\n\n$CURRENT_OBS" \ --arg model "$OBSERVER_MODEL" \ '{ model: $model, messages: [ {role: "system", content: $system}, {role: "user", content: $obs} ], max_tokens: 4000, temperature: 0.2 }') ``` ```bash RESPONSE=$(curl -s --max-time 120 "$LLM_BASE_URL/chat/completions" \ -H "Authorization: Bearer $LLM_API_KEY" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" 2>/dev/null) ``` ### Technical Analysis The core functionality requires some LLM processing, and the documentation discloses that transcripts are sent to an LLM. However, the implementation does not apply secret redaction, data classification, endpoint allowlisting, TLS enforcement, or per-session exclusion controls. `LLM_BASE_ ...[truncated 1762 chars]
Remediation
View remediation

T06 · System Persistence

Warning
Location
scripts/setup.sh:96
Finding

Setup Automatically Installs and Enables a Persistent Transcript Watcher

Content
View full analysis
"$SYSTEMD_DIR/total-recall-watcher.service" << EOF [Unit] Description=Total Recall — Reactive Observer Watcher After=default.target [Service] Type=simple ExecStart=$SKILL_DIR/scripts/observer-watcher.sh Restart=on-failure RestartSec=30 Environment=OPENCLAW_WORKSPACE=$WORKSPACE [Install] WantedBy=default.target EOF systemctl --user daemon-reload systemctl --user enable total-recall-watcher.service systemctl --user start total-recall-watcher.service 2>/dev/null || true echo "✅ Watcher service installed and started" fi ``` ### Technical Analysis Running the general setup script automatically writes a systemd user unit, enables it for future logins, and starts it immediately whenever inotify and a systemd user session are available. The service continuously monitors OpenClaw session transcript modifications and launches observer processing after an activity threshold. It is configured to restart after failure. This persistence survives the setup process and future session resets. Persistent observation is relevant to the declared autonomous-memory function. However, the project also states that the cron observer provides full coverage without the watcher. The reactive watcher is therefore optional redundancy rather than the minimum privilege or persistence required for the feature. Automatically enabling it without a dedicated opt-in exceeds least-privilege expectations. ### Attack Path 1. The user runs `scripts/setup.sh` to create the memory directory structure. 2. The script detects systemd ...[truncated 717 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/dream-cycle.sh:111
Finding

Dream Cycle Helper Allows Path Traversal and Over-Broad File Writes

Content
View full analysis
"; exit 1; } ensure_dirs local archive_path="$OPENCLAW_WORKSPACE/$archive_file" mkdir -p "$(dirname "$archive_path")" local payload payload="$(json_input_or_arg "$json_arg")" printf '%s\n' "$payload" | jq -e . >/dev/null 2>&1 || { err "Archive payload is not valid JSON" exit 1 } local tmp="${archive_path}.tmp" { local today today="$(ISO_DATE_UTC)" echo "# Archived Observations — $today" echo echo "Archived by Dream Cycle nightly run." echo echo "---" echo printf '%s\n' "$payload" | jq -r ' if type == "array" then . else .items // [] end | to_entries[] | .value as $o | "## \($o.id)", "**Original date**: \($o.original_date)", "**Impact**: \($o.impact)", "**Archived reason**: \($o.archived_reason)", "\($o.full_text)", "", "---", "" ' } > "$tmp" [ -s "$tmp" ] || { rm -f "$tmp"; err "Generated archive file is empty"; exit 1; } mv "$tmp" "$archive_path" } ``` The update command similarly accepts an unrestricted source path: ```bash cmd_update_observations() { local new_file="${1:-}" [ -n "$new_file" ] || { err "Usage: dream-cycle.sh update-observations "; exit 1; } local source_path="$OPENCLAW_WORKSPACE/$new_file" [ -f "$source_path" ] || { err "New observations file not found: $source_path"; exit 1; } require_file "$OBSERVATIONS_FILE" ...[truncated 3263 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (83)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill explicitly processes local session transcripts and sends them to an external LLM provider, but that network/data-flow risk is understated by the 'no database, no vectors' framing and absent permission declarations. In a memory skill, transcript access is highly sensitive because it may include credentials, personal data, and proprietary information from prior conversations.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/dream-cycle.sh` | Shell helper: preflight, archive, update-observations, write-log, write-metrics, validate, rollback |

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

A conversation memory skill normally needs access to conversation data, not periodic bash execution of a workspace script. Scheduling an agent to run shell commands every 15 minutes increases the attack surface substantially: if the script path, workspace contents, or downstream prompt/script logic are modified or influenced, the system can repeatedly execute unintended code without user intervention.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The script uses eval on data extracted from .env, which can execute arbitrary shell code if the .env file is maliciously modified or untrusted. This turns credential loading into a code-execution primitive, and because the script may run in a shared workspace, the risk is more serious than ordinary environment-variable parsing.

Content

Scanner excerpt · scripts/backfill-importance.sh (reported line 15)May include surrounding context.

sh
BACKUP_FILE="${OBSERVATIONS_FILE}.pre-backfill.bak"

# Source env
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  eval "$(grep -E '^(ANTHROPIC_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/backfill-importance.sh (reported line 17)May include surrounding context.

sh
# Source env
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  eval "$(grep -E '^(ANTHROPIC_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/observer-agent.sh (reported line 38)May include surrounding context.

sh
# Source env
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  eval "$(grep -E '^(ANTHROPIC_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.sh (reported line 58)May include surrounding context.

sh
# Source env
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  eval "$(grep -E '^(ANTHROPIC_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.sh (reported line 60)May include surrounding context.

sh
# Source env
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  eval "$(grep -E '^(ANTHROPIC_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level documentation frames the helper as safe, yet the rollback path forcibly rewinds repository history with 'git reset --hard HEAD~1', which can discard unrelated workspace changes. This is an active contradiction between the file's stated safety intent and actual behavior.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

Loading .env at startup gives the script access to arbitrary workspace credentials and tokens that are not obviously required for local memory compaction. Even if this script does not exfiltrate them directly, expanding secret access for an autonomous helper increases blast radius and enables credential exposure through later code, subprocesses, or accidental logging.

Content

Scanner excerpt · scripts/dream-cycle.sh (reported line 11)May include surrounding context.

sh
SKILL_DIR="$OPENCLAW_WORKSPACE/skills/total-recall"

# Load environment if present
if [ -f "$OPENCLAW_WORKSPACE/.env" ]; then
  set -a
  # shellcheck disable=SC1090
  source "$OPENCLAW_WORKSPACE/.env"

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

Using source on .env is especially dangerous because it treats the file as executable shell, allowing command execution in addition to secret loading. In a workspace-integrated skill, a poisoned .env can become an execution vector and compromise both local data and any credentials present in the environment.

Content

Scanner excerpt · scripts/dream-cycle.sh (reported line 14)May include surrounding context.

sh
if [ -f "$OPENCLAW_WORKSPACE/.env" ]; then
  set -a
  # shellcheck disable=SC1090
  source "$OPENCLAW_WORKSPACE/.env"
  set +a
fi

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The rollback command performs git reset --hard HEAD~1 on the entire workspace, which destructively discards tracked changes outside the skill's own files. In this skill context, a memory helper has no clear need for repository-wide history-rewriting capability, so misuse or accidental invocation can cause significant data loss and sabotage unrelated work.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The script uses eval on lines extracted from .env, which creates a code execution primitive if an attacker can modify that file. Even though grep restricts matched keys, shell expansions or command substitutions in the value can still be evaluated, turning configuration loading into arbitrary command execution and secret compromise.

Content

Scanner excerpt · scripts/observer-agent.sh (reported line 35)May include surrounding context.

sh
LOCK_FILE="/tmp/total-recall-reflector-$(id -u).lock"

# Source env if available (grep-guard: only export KEY=VALUE lines)
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Load provider config + backward compatible OPENROUTER key
  eval "$(grep -E '^(LLM_BASE_URL|LLM_API_KEY|LLM_MODEL|OPENROUTER_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script intentionally aggregates recent user and assistant messages, including existing observation context, and forwards them to an external LLM for compression. Since there is no content classification, secret stripping, or sensitivity gating, any confidential material present in conversations can be disclosed to a third party and potentially retained or logged upstream.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The script reads $WORKSPACE/.env and uses eval on content derived from it, which turns a configuration file into executable shell code. If an attacker can modify .env, they can achieve arbitrary command execution in the context of the watcher whenever it starts, and the fact that this skill runs automatically/reactively makes that context more dangerous.

Content

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

sh
ACCUMULATED_LINES=0

# Safe env loading
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Only load OPENROUTER_API_KEY (minimal credential exposure)
  eval "$(grep -E '^OPENROUTER_API_KEY=' "$WORKSPACE/.env" 2>/dev/null)" || true

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

Although the comment says only OPENROUTER_API_KEY is loaded, the mechanism still relies on eval of .env-derived text, so the risk is code execution rather than mere credential access. In this skill's context, an always-on observer/watcher increases exposure because a poisoned workspace file can be executed automatically during routine operation, potentially exposing the API key and compromising the user environment.

Content

Scanner excerpt · scripts/observer-watcher.sh (reported line 32)May include surrounding context.

sh
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Only load OPENROUTER_API_KEY (minimal credential exposure)
  eval "$(grep -E '^OPENROUTER_API_KEY=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The script uses eval on content extracted from .env, which enables command execution if an attacker can modify that file. A malicious value such as command substitution in an apparently allowed variable assignment would run with the privileges of the script, leading to code execution and likely credential exposure or workspace compromise.

Content

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

sh
LOCK_FILE="/tmp/total-recall-reflector-$(id -u).lock"

# Safe env loading
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Load provider config + backward compatible OPENROUTER key
  eval "$(grep -E '^(LLM_BASE_URL|LLM_API_KEY|LLM_MODEL|OPENROUTER_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

This finding refers to the same unsafe .env loading block: values from .env are evaluated in the shell, allowing attacker-controlled code execution during environment setup. Because the script handles API credentials and writes to workspace memory files, exploitation could expose secrets, redirect exfiltration to attacker-controlled endpoints, or tamper with stored observations.

Content

Scanner excerpt · scripts/reflector-agent.sh (reported line 32)May include surrounding context.

sh
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Load provider config + backward compatible OPENROUTER key
  eval "$(grep -E '^(LLM_BASE_URL|LLM_API_KEY|LLM_MODEL|OPENROUTER_API_KEY)=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The setup script reads credentials from $WORKSPACE/.env and later uses eval on content derived from that file. Even though the grep is intended to restrict loading to OPENROUTER_API_KEY, using eval on attacker-controlled or malformed .env content can lead to shell code execution during setup if the workspace or .env file is compromised. In a memory/observer skill that is meant to run automatically, this becomes more dangerous because setup is likely run in a trusted local environment and the same workspace may be shared across agent components.

Content

Scanner excerpt · scripts/setup.sh (reported line 50)May include surrounding context.

sh
fi

# --- Check API key ---
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Only load OPENROUTER_API_KEY (minimal credential exposure)
  eval "$(grep -E '^OPENROUTER_API_KEY=' "$WORKSPACE/.env" 2>/dev/null)" || true

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

This finding is part of the same unsafe credential-loading block that uses eval on data sourced from .env. If an attacker can modify the workspace .env file, they may inject shell syntax that executes during setup, turning a simple credential read into arbitrary command execution. Because this skill installs persistence mechanisms and is intended for unattended operation, compromise here can have broader downstream impact.

Content

Scanner excerpt · scripts/setup.sh (reported line 53)May include surrounding context.

sh
if [ -f "$WORKSPACE/.env" ]; then
  set -a
  # Only load OPENROUTER_API_KEY (minimal credential exposure)
  eval "$(grep -E '^OPENROUTER_API_KEY=' "$WORKSPACE/.env" 2>/dev/null)" || true
  set +a
fi
if [ -z "${OPENROUTER_API_KEY:-}" ]; then

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
INSTALL-AGENT.md:31