Back to skill

Security audit

Alex Session Wrap-Up

Security checks for vulnerabilities and agentic risk

Overview

This session wrap-up skill is mostly coherent, but it can automatically push sensitive local files and send memory content to external AI services without enough user control.

Review before installing or running. At minimum, remove .env from git staging, stop sourcing dotenv files as shell code, add a dry-run and explicit confirmation before commit or push, restrict staged files to a narrow allowlist, require opt-in before external AI calls, redact memory content before sending it, and validate any model output before writing it to memory.

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
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/session-wrap-up.sh:35
Finding
Automatic Commit and Push Can Expose Sensitive Workspace Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/session-wrap-up.sh`, lines 35-47 **Vulnerability Type**: Automatic disclosure of sensitive and unrelated repository content **Risk Level**: High ### Vulnerable Code ```bash # Only commit text/config files, skip binaries and media if git rev-parse --git-dir >/dev/null 2>&1; then # Add only text/config files git add *.md *.txt *.json *.sh *.yaml *.yml *.env 2>/dev/null || true git add docs/* scripts/* skills/* memory/* 2>/dev/null || true git add AGENTS.md USER.md SOUL.md MEMORY.md TOOLS.md 2>/dev/null || true git add projects/*/README.md projects/*/notes/* 2>/dev/null || true if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then echo "Committing text/config changes..." git commit -m "Auto-wrap-up: $(date -Iseconds)" 2>/dev/null || true if git remote get-url origin >/dev/null 2>&1; then git push origin HEAD 2>/dev/null && echo " ✓ Pushed to origin" || echo " ⚠ Push failed" fi ``` ### Technical Analysis The script indiscriminately stages broad classes of workspace files, including `.env` files, memory records, user-related files, agent instruction files, and tool configuration. These file categories are particularly likely to contain API keys, personal information, internal project details, or privileged agent state. The subsequent `git commit` does not limit the commit to files staged by this invocation. Any content already in the Git index is also included. The resulting commit is automatically pushed to the repository configured as `origin`, without validating whether the destination is trusted, private, or expected and without presenting the staged diff for user approval. Although shipping work is part of the declared functionality, automatically transmitting sensitive agent and environment files exceeds the minimum privileges necessary to commit ordinary work products. ### Attack Path 1. A secret, private memory entry, or sensitive instruction is s ...[truncated 1224 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never automatically stage `.env` files, secrets, memory records, identity files, or agent-control files. - Replace broad glob patterns with a narrowly defined allowlist of expected work-product paths. - Detect a nonempty Git index before staging and abort rather than including pre-existing staged changes. - Use `git diff --cached --name-only` and secret scanning to inspect the exact proposed commit. - Display the staged diff and require explicit user confirmation before committing. - Validate the remote URL against a configured allowlist and require separate confirmation before pushing. - Do not suppress commit and push errors, because hidden failures can make the reported state inaccurate. - Add sensitive paths to `.gitignore`, while recognizing that `.gitignore` does not protect files already tracked. - If secrets have already been pushed, rotate them immediately and remove them from repository history using an appropriate history-rewriting process. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/session-wrap-up.sh:14
Finding
Arbitrary Shell Execution Through Sourced Environment File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/session-wrap-up.sh`, lines 14-18 **Vulnerability Type**: Unsafe execution of configuration data as shell code **Risk Level**: High ### Vulnerable Code ```bash # Load env if [[ -f "$WORKSPACE/../.env" ]]; then set -a source "$WORKSPACE/../.env" set +a fi ``` ### Technical Analysis Bash `source` does not parse a file as passive key-value configuration. It executes the file in the current shell process. Consequently, the `.env` file can contain command substitutions, function definitions, redirects, shell options, external commands, or modifications to variables such as `PATH`. The script uses a fixed path, `/home/xbill/.openclaw/.env`, but performs no ownership, permission, integrity, or syntax validation before executing it. Any party capable of modifying that file can execute arbitrary commands with all permissions available to the account running the wrap-up script. Because execution occurs near the beginning of the script, malicious configuration can also alter commands or environment state used by all subsequent phases. ### Attack Path 1. An attacker, compromised process, or unsafe setup procedure gains write access to `/home/xbill/.openclaw/.env`. 2. The attacker inserts shell code, for example a command substitution or an ordinary shell command, rather than a simple environment assignment. 3. The user or agent invokes `scripts/session-wrap-up.sh`. 4. The `source` command evaluates the malicious content in the current Bash process. 5. The payload executes with the invoking user's filesystem, network, Git, and credential access. 6. The payload may then modify workspace data, read credentials, change Git configuration, or perform other actions available to that user. ### Impact Assessment Successful exploitation provides arbitrary command execution with the privileges of the user or agent running the skill. This can expose all files readable by that account and permit modification o ...[truncated 289 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not use `source`, `.`, or `eval` to load dotenv configuration. - Prefer receiving `OPENAI_API_KEY` and `OPENROUTER_API_KEY` from the already established process environment. - If a dotenv file is required, parse it with a library or strict parser that accepts only explicitly allowed variable names and literal values. - Reject command substitutions, shell metacharacters, redirects, function syntax, multiline values, and unexpected keys. - Verify that the configuration file is a regular file, owned by the expected user, and not writable by group or other users. - Use a minimal environment for subprocesses and an explicit trusted `PATH`. - Document the exact configuration keys required so that arbitrary shell configuration is unnecessary. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/session-wrap-up.sh:94
Finding
Unredacted Memory Entries Are Transmitted to Third-Party Model APIs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/session-wrap-up.sh`, lines 63-65 and 94-110 **Vulnerability Type**: Sensitive information disclosure to external services **Risk Level**: High ### Vulnerable Code ```bash LEARNINGS="" if [[ -f "$MEMORY_FILE" ]]; then LEARNINGS=$(grep -E '^- ' "$MEMORY_FILE" 2>/dev/null | head -20 || true) ``` ```bash if [[ -n "$LEARNINGS" && -n "${OPENAI_API_KEY:-}" ]]; then PATTERN_RESULT=$(curl -sS --max-time 30 "https://api.openai.com/v1/chat/completions" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"model\": \"$MODEL\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \ 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("choices",[{}])[0].get("message",{}).get("content","Error"))') \ || PATTERN_RESULT="API error" elif [[ -n "$LEARNINGS" && -n "${OPENROUTER_API_KEY:-}" ]]; then PATTERN_RESULT=$(curl -sS --max-time 30 "https://openrouter.ai/api/chat/v1/chat/completions" \ -H "Authorization: Bearer $OPENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"model\": \"openai/gpt-4o-mini\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \ 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("choices",[{}])[0].get("message",{}).get("content","Error"))') \ || PATTERN_RESULT="API error" ``` ### Technical Analysis The script extracts up to 20 bullet-form memory entries and places them verbatim into a model prompt. If either supported API key is available, that prompt is transmitted to OpenAI or OpenRouter. No data classification, secret scanning, redaction, minimization, consent prompt, or preview occurs before transmission. Memory entries can contain conversation-derived personal information, credentials, private project information, internal URLs, or other material that the user did not ...[truncated 1296 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make external model analysis explicitly opt-in for each invocation or establish a clear, user-approved policy. - Show the exact content and destination before sending it. - Apply secret detection and redaction for API keys, tokens, passwords, private keys, personal data, and internal identifiers. - Minimize transmitted content by generating local summaries or extracting only non-sensitive metadata. - Prefer a local model or deterministic local pattern analysis where feasible. - Permit users to disable each provider independently. - Clearly document provider processing and retention implications. - Construct JSON with a proper JSON encoder rather than manual string interpolation, preventing malformed requests when memory contains quotes, backslashes, or control characters. - Log that external transmission occurred without logging the sensitive request body. ]]>

T02 · Agent Memory Poisoning

Error
Location
scripts/session-wrap-up.sh:76
Finding
Untrusted Model Output Is Persisted Into Long-Term Agent Memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/session-wrap-up.sh`, lines 76-90 and 124-130 **Vulnerability Type**: Prompt injection leading to persistent memory poisoning **Risk Level**: High ### Vulnerable Code ```bash PROMPT="You are a pattern detection assistant. Analyze the following memory entries from today and find: 1. Repeated questions or requests 2. Things the user had to ask about repeatedly 3. Automation opportunities Memory entries: $LEARNINGS Respond in this format: PATTERNS: - [pattern or 'No significant patterns'] AUTOMATION_SUGGESTIONS: - [suggestion or 'None']" ``` ```bash if [[ -n "$PATTERN_RESULT" && "$PATTERN_RESULT" != "API error" && "$PATTERN_RESULT" != "Error" && "$PATTERN_RESULT" != "No significant patterns" ]]; then echo "Patterns detected, logging..." echo "" >> "$MEMORY_FILE" echo "### Wrap-up Patterns ($TODAY)" >> "$MEMORY_FILE" echo "$PATTERN_RESULT" >> "$MEMORY_FILE" echo " ✓ Patterns saved" else ``` ### Technical Analysis The memory entries are interpolated directly into the instruction prompt without a strong trust boundary, structured data encoding, or an instruction that their contents must be treated only as quoted data. A malicious or compromised memory entry can therefore contain prompt-injection instructions intended to control the model response. The response is accepted as trustworthy based only on a few exact-string exclusions. Any other response is appended verbatim to the daily memory file. There is no schema enforcement, semantic validation, content filtering, provenance marker, or user approval. This creates a persistent trust-boundary violation: untrusted local memory influences a remote model, and the model's attacker-influenced output is then written back into long-term state that may be consumed by future sessions. ### Attack Path 1. An attacker or untrusted data source causes a bullet entry to be written into the current daily memory file. 2. The entry contains instructio ...[truncated 1075 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat all memory entries as untrusted data rather than instructions. - Send memory in a separately encoded data field and use a strong system instruction stating that embedded directives must not be followed. - Require structured JSON output with a strict schema, fixed field lengths, and enumerated output types. - Validate the parsed response and reject extra fields, instruction-like language, links, executable content, and attempts to modify agent behavior. - Store generated patterns in a quarantined or review-pending file rather than active memory. - Require explicit user approval before promoting model-generated content into persistent agent state. - Record provenance so future consumers can distinguish user-authored memory from model-generated analysis. - Limit the maximum response size and normalize output before storage. - Prefer deterministic local pattern extraction for data that will affect long-term state. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description understates several high-risk behaviors: external API calls, remote git pushes, and loading secrets from a .env file. This mismatch can cause users or orchestrators to invoke the skill without understanding that code, metadata, or session-derived content may be exfiltrated or that remote state will be modified.

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill lacks a clear warning that it may automatically commit changes, push to a remote repository, and modify local memory or agent files. These are significant side effects that can publish unfinished work, leak sensitive material, or alter future agent behavior without informed consent.

Missing User Warnings

High
Confidence
97% confidence
Finding
The markdown states that pattern detection uses external model providers but omits a privacy warning that session-derived learnings may be sent off-box. Because the skill scans conversation and memory entries, it may transmit sensitive project details, credentials, or personal data to third parties without the user's awareness.

Credential Access

High
Category
Privilege Escalation
Content
MODEL="gpt-4o-mini"

# Load env
if [[ -f "$WORKSPACE/../.env" ]]; then
  set -a
  source "$WORKSPACE/../.env"
  set +a
Confidence
98% confidence
Finding
Reading a sibling .env file gives the script access to stored credentials and sensitive configuration that may be unrelated to wrap-up behavior. In combination with later network and git operations, this creates an unnecessary credential exposure surface and raises the consequences of any future script change or compromise.

Credential Access

High
Category
Privilege Escalation
Content
# Load env
if [[ -f "$WORKSPACE/../.env" ]]; then
  set -a
  source "$WORKSPACE/../.env"
  set +a
fi
Confidence
98% confidence
Finding
The actual source command executes the contents of the .env file in the current shell, not merely parses key/value pairs. That means malformed or malicious content in the file could run arbitrary shell code under the user's account, making this more severe than passive credential reading.

Credential Access

High
Category
Privilege Escalation
Content
# Only commit text/config files, skip binaries and media
if git rev-parse --git-dir >/dev/null 2>&1; then
  # Add only text/config files
  git add *.md *.txt *.json *.sh *.yaml *.yml *.env 2>/dev/null || true
  git add docs/* scripts/* skills/* memory/* 2>/dev/null || true
  git add AGENTS.md USER.md SOUL.md MEMORY.md TOOLS.md 2>/dev/null || true
  git add projects/*/README.md projects/*/notes/* 2>/dev/null || true
Confidence
99% confidence
Finding
The script explicitly stages *.env files for commit. This can capture secrets such as API keys and service credentials into git history, and because the script may push to origin automatically, those secrets can be rapidly propagated to remote repositories and other collaborators.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill description says it commits unpushed work, but the script also pushes to the remote origin automatically. That can exfiltrate local changes beyond the machine boundary, including notes, scripts, memory files, or accidentally staged sensitive data, and materially exceeds the stated behavior users might expect.

External Script Fetching

High
Category
Supply Chain
Content
PATTERN_RESULT=""

if [[ -n "$LEARNINGS" && -n "${OPENAI_API_KEY:-}" ]]; then
  PATTERN_RESULT=$(curl -sS --max-time 30 "https://api.openai.com/v1/chat/completions" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"$MODEL\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("choices",[{}])[0].get("message",{}).get("content","Error"))') \
    || PATTERN_RESULT="API error"
elif [[ -n "$LEARNINGS" && -n "${OPENROUTER_API_KEY:-}" ]]; then
  PATTERN_RESULT=$(curl -sS --max-time 30 "https://openrouter.ai/api/chat/v1/chat/completions" \
    -H "Authorization: Bearer $OPENROUTER_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"openai/gpt-4o-mini\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool scope even though its documented behavior includes shell operations and network access. This weakens least-privilege controls and makes it easier for the skill to perform sensitive actions such as pushing code or sending data externally without clear user-approved boundaries.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The automatic trigger 'End of significant work session (optional)' is vague and can cause the skill to run without a clear, user-confirmed boundary. In this skill's context, accidental activation is dangerous because execution may commit files, push to remotes, and persist or transmit session-derived data.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The script sources an entire sibling .env file into its environment, importing every variable and secret whether needed or not. This expands the script's access to unrelated credentials and configuration, and because the same script later performs network transmission and git operations, over-broad secret loading increases the blast radius if the script misbehaves or is modified.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script automatically commits and may push files without asking for confirmation. In a session-wrap-up context, users may not inspect staged files, so sensitive notes, environment files, or unintended workspace changes can be persisted locally or sent remotely without review.

External Transmission

Medium
Category
Data Exfiltration
Content
PATTERN_RESULT=""

if [[ -n "$LEARNINGS" && -n "${OPENAI_API_KEY:-}" ]]; then
  PATTERN_RESULT=$(curl -sS --max-time 30 "https://api.openai.com/v1/chat/completions" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"$MODEL\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \
Confidence
95% confidence
Finding
The static URL match reflects a genuine outbound network destination used for data transfer. In this skill context, outbound transmission is more dangerous because it is tied to session memory analysis and happens in an automation script that may run routinely.

External Transmission

Medium
Category
Data Exfiltration
Content
PATTERN_RESULT=""

if [[ -n "$LEARNINGS" && -n "${OPENAI_API_KEY:-}" ]]; then
  PATTERN_RESULT=$(curl -sS --max-time 30 "https://api.openai.com/v1/chat/completions" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"$MODEL\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \
Confidence
95% confidence
Finding
The static URL match reflects a genuine outbound network destination used for data transfer. In this skill context, outbound transmission is more dangerous because it is tied to session memory analysis and happens in an automation script that may run routinely.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script sends session memory contents to external AI providers for pattern detection without explicit consent or a meaningful warning. Session memory can contain sensitive prompts, internal notes, project details, or user data, so transmitting it off-host creates a privacy and data-governance risk.

External Transmission

Medium
Category
Data Exfiltration
Content
2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("choices",[{}])[0].get("message",{}).get("content","Error"))') \
    || PATTERN_RESULT="API error"
elif [[ -n "$LEARNINGS" && -n "${OPENROUTER_API_KEY:-}" ]]; then
  PATTERN_RESULT=$(curl -sS --max-time 30 "https://openrouter.ai/api/chat/v1/chat/completions" \
    -H "Authorization: Bearer $OPENROUTER_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\": \"openai/gpt-4o-mini\", \"messages\": [{\"role\": \"user\", \"content\": \"$PROMPT\"}], \"max_tokens\": 300}" \
Confidence
97% confidence
Finding
This branch sends the same session-derived content to OpenRouter, again causing third-party disclosure of local memory content. The danger is heightened because it is an alternate path, so users may not realize their data could be sent to different providers depending on available keys.