Back to skill

Security audit

Session Memory Flush

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent with its memory-flush purpose, but it automatically installs a recurring watcher that broadly reads OpenClaw transcripts, may send raw transcript text to a configured LLM endpoint, and persists derived memory.

Install only if you intentionally want a background job to scan all OpenClaw sessions visible to your account and write derived summaries into workspace memory. Before enabling it, review the generated systemd or cron entry, prefer an internal or trusted HTTPS LLM endpoint, avoid putting secrets in transcripts, and consider running dry-run or local-only mode in sensitive environments.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T02 · Agent Memory Poisoning

Error
Location
watcher.py:572
Finding

Untrusted transcript content can poison persistent Agent memory

Content
View full analysis
Optional[str]: payload = { "model": model_cfg["model"], "messages": [ {"role": "system", "content": prompt or "请总结 session 中值得长期记住的信息。"}, {"role": "user", "content": transcript}, ], "temperature": 0.2, } ``` ```python transcript = read_transcript_text(transcript_path) if not transcript.strip(): return f"skip {session_id}: empty transcript" summary = call_llm_summary(transcript, session=session) or local_summary(transcript) if "无重要可回收记忆" in summary: return f"skip {session_id}: no important memory" entry = build_memory_entry(session, session_id, summary) if dry_run: return f"dry-run {session_id}: would write {len(entry)} chars from {transcript_path}" memory_path = append_memory(entry, session=session) ``` ### Technical Analysis The implementation treats an entire session transcript as an ordinary LLM user message. Transcript content can include messages supplied by untrusted chat participants. The summarization prompt describes the desired output but does not explicitly instruct the model to treat commands embedded in the transcript as inert data or prohibit following transcript-level instructions. The generated summary is trusted without structural or semantic validation and is appended to a durable workspace memory file. Future Agent sessions may load that file as memory. Consequently, an instruction embedded in a transcript can cross the trust boundary from untrusted conversation data into trusted persistent context. The local fallback is also exposed to content injection because it selects and copies transcript lines based on ...[truncated 1404 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
watcher.py:572
Finding

Raw session transcripts are transmitted to dynamically configured network endpoints before redaction

Content
View full analysis
Optional[str]: payload = { "model": model_cfg["model"], "messages": [ {"role": "system", "content": prompt or "请总结 session 中值得长期记住的信息。"}, {"role": "user", "content": transcript}, ], "temperature": 0.2, } req = urllib.request.Request( f"{model_cfg['base_url']}/chat/completions", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {model_cfg['api_key']}", "Content-Type": "application/json", }, method="POST", ) try: with urllib.request.urlopen(req, timeout=60) as resp: data = json.loads(resp.read().decode("utf-8")) ``` ```python def call_openai_responses_summary(model_cfg: Dict[str, str], prompt: str, transcript: str) -> Optional[str]: payload = { "model": model_cfg["model"], "input": [ {"role": "system", "content": prompt or "请总结 session 中值得长期记住的信息。"}, {"role": "user", "content": transcript}, ], "stream": True, } req = urllib.request.Request( f"{model_cfg['base_url']}/responses", data=json.dumps(payload).encode("utf-8"), header ...[truncated 2372 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
install.sh:163
Finding

Unescaped configuration values allow injection into generated systemd and cron definitions

Content
View full analysis
/dev/null 2>&1 && systemctl --user list-timers >/dev/null 2>&1; then mkdir -p "$SYSTEMD_USER_DIR" cat > "$SYSTEMD_USER_DIR/$SERVICE_NAME.service" </dev/null | grep -v "$CRON_MARKER" > "$TMP_CRON" || true echo "*/$TIMER_MINUTES * * * * cd $SKILL_DIR && OPENCLAW_BIN=$OPENCLAW_BIN SESSION_MEMORY_DM_IDLE_MINUTES=$DM_IDLE_MINUTES SESSION_MEMORY_GROUP_IDLE_MINUTES=$GROUP_IDLE_MINUTES SESSION_MEMORY_SCAN_WINDOW_DM=$SCAN_WINDOW_DM SESSION_MEMORY_SCAN_WINDOW_GROUP=$SCAN_WINDOW_GROUP SESSION_MEMORY_OUTPU ...[truncated 2919 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (23)

Tainted flow: 'req' from os.environ.get (line 614, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
99% confidence
Finding

The function sends raw session transcript content to a network endpoint whose base URL, model, and credentials can come from environment variables or configuration, with no allowlist, trust validation, or sensitivity filtering. This creates a direct transcript exfiltration path to arbitrary external services, potentially leaking secrets, user data, and internal context.

Content

Scanner excerpt · watcher.py (reported line 593)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=60) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except (urllib.error.URLError, TimeoutError, json.JSONDecodeError):
        return None

Tainted flow: 'req' from os.environ.get (line 614, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
99% confidence
Finding

This second network path has the same core issue: full transcript data is posted to an externally configurable /responses endpoint without destination restrictions or content minimization. Because the skill's purpose is memory recovery across sessions, the transferred data can include especially broad and sensitive historical context.

Content

Scanner excerpt · watcher.py (reported line 624)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=90) as resp:
            body = resp.read().decode("utf-8", errors="replace")
    except (urllib.error.URLError, TimeoutError):
        return None

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on runtime behavior for collecting session context from OpenClaw sessions and persisting it into workspace memory before sessions are released. The supplied code does none of that. Instead, it performs teardown of scheduling infrastructure by removing systemd and cron entries for a service named openclaw-session-memory-flush. While an uninstall script could be part of the broader skill package, this specific code chunk's purpose is materially different from the declared functional behavior and exercises undeclared capabilities involving systemd and crontab modification. Therefore this code chunk does not accurately represent the declared description.

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 156)May include surrounding context.

md
- `watcher.py` 只在运行时读取本机 `openclaw.json` 或环境变量中的 API key 用于请求模型,不会把 API key 写入 `state`、memory markdown 或日志。

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · uninstall.sh (reported line 10)May include surrounding context.

sh
if command -v systemctl >/dev/null 2>&1; then
  systemctl --user disable --now "$SERVICE_NAME.timer" >/dev/null 2>&1 || true
  rm -f "$SYSTEMD_USER_DIR/$SERVICE_NAME.service"
  rm -f "$SYSTEMD_USER_DIR/$SERVICE_NAME.timer"
  systemctl --user daemon-reload >/dev/null 2>&1 || true
fi

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · uninstall.sh (reported line 11)May include surrounding context.

sh
if command -v systemctl >/dev/null 2>&1; then
  systemctl --user disable --now "$SERVICE_NAME.timer" >/dev/null 2>&1 || true
  rm -f "$SYSTEMD_USER_DIR/$SERVICE_NAME.service"
  rm -f "$SYSTEMD_USER_DIR/$SERVICE_NAME.timer"
  systemctl --user daemon-reload >/dev/null 2>&1 || true
fi

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill is described as writing recovered context into workspace memory, but the implementation may first transmit full transcripts to an external LLM service for summarization. That mismatch increases privacy and trust risk because operators may reasonably assume data stays local when it can actually leave the environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documentation describes behavior that reads environment/config, scans session transcripts, writes memory files, invokes shell commands, and may call an external LLM provider, yet it declares no explicit tool scope or permission boundaries. In a skill system, that omission weakens reviewability and least-privilege enforcement, making it easier for a caller to invoke broader file, shell, or network actions than users may expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level description is written entirely in Chinese and does not indicate that other languages are supported or that Chinese is required for a specific regional/compliance reason. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The installer persistently registers a systemd user timer or cron job without any confirmation prompt or explicit upfront disclosure before making the change. Persistent scheduled execution expands the skill's reach beyond a one-time install and can surprise users by repeatedly scanning sessions and writing memory data in the background.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
96% confidence
Finding

Enabling and starting a user systemd timer establishes background persistence that survives the installer invocation. Given this skill's purpose—periodically scanning OpenClaw sessions and summarizing transcript content into memory files—silent persistence materially increases the chance of unexpected data collection and repeated execution.

Content

Scanner excerpt · install.sh (reported line 200)May include surrounding context.

sh
EOF

  systemctl --user daemon-reload
  systemctl --user enable --now "$SERVICE_NAME.timer"
  echo "Installed systemd user timer: $SERVICE_NAME.timer"
  systemctl --user status "$SERVICE_NAME.timer" --no-pager || true
else

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

Installing a cron entry causes recurring execution after the initial install, which is a persistence mechanism. In this skill's context, the persistent task repeatedly inspects session metadata/transcripts and writes derived memory, so unauthorized or insufficiently disclosed persistence increases privacy and operational risk.

Content

Scanner excerpt · install.sh (reported line 204)May include surrounding context.

sh
echo "Installed systemd user timer: $SERVICE_NAME.timer"
  systemctl --user status "$SERVICE_NAME.timer" --no-pager || true
else
  if ! command -v crontab >/dev/null 2>&1; then
    echo "ERROR: neither systemd user timer nor crontab is available"
    exit 1
  fi

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file’s title and all instructional text require the summarizer to operate in Chinese, including the required output structure and wording. This imposes a specific language/locale without offering the user a choice or documenting a justified region-specific constraint, which matches the natural-language policy violation criteria.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · uninstall.sh (reported line 15)May include surrounding context.

sh
systemctl --user daemon-reload >/dev/null 2>&1 || true
fi

if command -v crontab >/dev/null 2>&1; then
  TMP_CRON="$(mktemp)"
  crontab -l 2>/dev/null | grep -v "$CRON_MARKER" > "$TMP_CRON" || true
  crontab "$TMP_CRON" || true

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · install.sh (reported line 210)May include surrounding context.

sh
if command -v crontab >/dev/null 2>&1; then
  TMP_CRON="$(mktemp)"
  crontab -l 2>/dev/null | grep -v "$CRON_MARKER" > "$TMP_CRON" || true
  crontab "$TMP_CRON" || true
  rm -f "$TMP_CRON"
fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · uninstall.sh (reported line 17)May include surrounding context.

sh
if command -v crontab >/dev/null 2>&1; then
  TMP_CRON="$(mktemp)"
  crontab -l 2>/dev/null | grep -v "$CRON_MARKER" > "$TMP_CRON" || true
  crontab "$TMP_CRON" || true
  rm -f "$TMP_CRON"
fi

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The command uses openclaw sessions --all-agents --json, then processes transcripts and writes memory across agent boundaries. In a multi-agent environment this broadens access beyond the implied current-session scope, increasing the chance of cross-agent data exposure and unintended aggregation of unrelated users' context.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · watcher.py (reported line 274)May include surrounding context.

python
raise RuntimeError("openclaw command not found; set OPENCLAW_BIN to the absolute path")

    cmd = [openclaw_bin, "sessions", "--all-agents", "--json"]
    proc = subprocess.run(
        cmd,
        text=True,
        stdout=subprocess.PIPE,

Tainted flow: 'cmd' from os.environ.get (line 273, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
88% confidence
Finding

OPENCLAW_BIN is taken from the environment and executed without validation, so anyone able to influence the runtime environment can cause an arbitrary executable to run instead of the expected openclaw binary. In a timer/agent automation context, that can become code execution under the agent's privileges.

Content

Scanner excerpt · watcher.py (reported line 274)May include surrounding context.

python
raise RuntimeError("openclaw command not found; set OPENCLAW_BIN to the absolute path")

    cmd = [openclaw_bin, "sessions", "--all-agents", "--json"]
    proc = subprocess.run(
        cmd,
        text=True,
        stdout=subprocess.PIPE,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Transcript contents are sent to an external LLM endpoint without any user-facing disclosure, consent flow, or even runtime logging that sensitive content is leaving the local environment. For a memory-flush skill that harvests prior conversations, lack of disclosure materially increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The hardcoded prompt text instructs the model in Chinese, and the local fallback summary also emits Chinese-only output. This imposes a specific language/locale behavior without any visible opt-in, choice, or documented region-specific justification.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill persists summarized transcript content into long-term workspace memory without sensitivity classification, redaction, retention limits, or access checks. Because transcripts may contain credentials, personal data, internal paths, or operational details, this creates a durable secondary store of potentially sensitive information and expands blast radius after compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The script creates a state directory and initializes a tracking file under the skill directory without warning the user first. While this is less severe than scheduler persistence, undisclosed writes to persistent state can still be problematic in security-sensitive environments because they change local state and may retain metadata about prior session processing.

Content

No source excerpt is available for this finding.