Back to skill

Security audit

Skill Insight

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a local skill-usage reporting tool, but its session scanner reads recent conversation history and tool-call data more broadly than users may expect.

Review this skill before installing if your OpenClaw sessions may contain secrets, private prompts, credentials, or sensitive tool arguments. Prefer manual recording or narrowly scoped structured logs over scan_sessions.py, and only add the cron entry if you understand what local files and logs it will create and how you will remove them later.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
  • 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 (1)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/scan_sessions.py:92
Finding

Excessive Access to OpenClaw Session History

Content
View full analysis

Vulnerability Details

File Location: scripts/scan_sessions.py, lines 92-171
Vulnerability Type: Excessive access to private session content beyond the minimum required for usage analysis
Risk Level: Medium

Vulnerable Code

python
def get_session_messages(session_key: str, limit=30):
    """Fetch messages for a session."""
    body, status = gateway_request(
        f"/sessions/{session_key}/messages?limit={limit}", timeout=8
    )
    if status == 200 and isinstance(body, list):
        return body

    try:
        result = subprocess.run(
            ["timeout", "8", "openclaw", "sessions", "history", session_key,
             "--limit", str(limit), "--json"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0 and result.stdout.strip():
            return json.loads(result.stdout)
    except Exception:
        pass
    return []

def extract_skills_from_content(content: str, valid_skills: set) -> list:
    """Extract skill invocations from message/exec content.

    Detection patterns (generic — no hardcoded skill names):
      1. Skill directory paths: /skills/<name>/
      2. Skill name word-boundary mentions (from registry)
    """
    found = []
    content_lower = content.lower()

    # 1. Skill directory paths: /skills/<name>/
    for match in re.finditer(r'/skills/([a-z0-9_-]+)/', content, re.IGNORECASE):
        skill = match.group(1).lower()
        if skill not in SKIP_SKILLS and skill in valid_skills:
            found.append(skill)

    for skill in valid_skills:
        if skill in SKIP_SKILLS:
            continue
        pattern = rf'\b{re.escape(skill)}\b'
        if re.search(pattern, content_lower):
            found.append(skill)

    seen = set()
    result = []
    for s in found:
        if s not in seen:
            seen.add(s)
            result.append(s)
 
...[truncated 4117 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace conversation scanning with structured execution or audit events containing only the invoked executable, skill identifier, timestamp, and result.
  2. If structured events are unavailable, restrict collection to messages explicitly identified as execution records rather than ordinary user or assistant content.
  3. Do not concatenate complete content, text, or toolCalls values. Extract only narrowly defined command-path fields and discard all other fields immediately.
  4. Require explicit opt-in before session-history scanning and clearly document the data scope, local processing behavior, retention policy, and limitations.
  5. Reduce default session and message limits and allow users to select which sessions may be inspected.
  6. Redact credentials, authorization headers, tokens, environment values, and sensitive tool arguments before any processing or logging.
  7. Ensure usage files and logs are created with user-only permissions and never store raw session content.
  8. Add tests confirming that ordinary conversation text and unrelated tool arguments are neither processed nor persisted.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose describes an analytics/insights capability focused on observing how skills are used and generating reports or recommendations. The supplied code does not analyze usage at all. Instead, it manages registry metadata for skills: reading/writing JSON files, creating a registry if missing, and adding or updating skill records with fields like category, description, installed flag, and timestamps. This is a materially different primary purpose from usage tracking/reporting, so the description does not accurately represent the code chunk's behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose centers on observing and reporting how skills are used. The actual code chunk does not perform any visible analytics, reporting, tracking, or recommendation logic. Instead, it simply delegates execution to add_skill.py, which suggests a different operational role: adding or managing a skill. While this may be part of a broader system, the provided chunk itself materially differs from the declared primary purpose, so this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documentation instructs users to run local scripts, set up cron jobs, scan session history, and write registry/usage data, but it does not declare any explicit tool scope or permissions boundary. That makes the effective capabilities broader and less auditable, increasing the chance that an agent or user grants shell, file, or environment access without understanding the exposure.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

The skill instructs users to install a persistent cron job that repeatedly scans session history and appends logs. Persistence itself is not automatically malicious here, but it creates ongoing automated access to potentially sensitive local data and may continue running without user awareness, especially if session contents include secrets or private prompts.

Content

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

Option A: For script-type skills only (easiest, automatic)

bash
# Add to crontab -e:
0 9 * * * cd ~/.openclaw/workspace/skills/skill-insight && bash scripts/cron_wrapper.sh >> ~/.local/log/skill-insight.log 2>&1

This runs daily and scans your session history for skill scripts that were executed via exec commands. Works for script access_type skills. Will NOT detect route-type skills.

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 · scripts/cron_wrapper.sh (reported line 5)May include surrounding context.

sh
# cron_wrapper.sh - Daily cron job wrapper for skill-insight
# Sets SKILL_USAGE_TRACKER_DIR so Python scripts resolve paths correctly.
#
# Add to crontab -e:
#   0 9 * * * cd ~/.openclaw/workspace/skills/skill-insight && bash scripts/cron_wrapper.sh >> ~/.local/log/skill-insight.log 2>&1

SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script fixes the report timezone to UTC+8 at L047 and labels it as Beijing time at L119, which imposes a specific locale on all users. Although --lang allows English or Chinese text, there is no equivalent choice for timezone/locale behavior or explanation that the tool is region-specific.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script scans recent sessions, pulls message history, and derives skill-usage records from conversation content, which is broader access than a user may reasonably expect from a reporting skill. Even if intended for analytics, this creates a privacy-sensitive data-processing path that can expose or retain information from unrelated session content without explicit consent or narrow minimization.

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 · scripts/scan_sessions.py (reported line 80)May include surrounding context.

python
return sessions

    try:
        result = subprocess.run(
            ["timeout", "5", "openclaw", "sessions", "--json", "--active", "1440"],
            capture_output=True, text=True, timeout=8
        )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code concatenates full message content, text fields, and serialized tool-call payloads for analysis, which may include sensitive prompts, secrets, or personal data unrelated to skill usage detection. Inspecting raw conversational and tool data is dangerous because it expands the skill's effective data access far beyond simple telemetry and increases the chance of privacy leakage or secondary misuse.

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 · scripts/scan_sessions.py (reported line 102)May include surrounding context.

python
return body

    try:
        result = subprocess.run(
            ["timeout", "8", "openclaw", "sessions", "history", session_key,
             "--limit", str(limit), "--json"],
            capture_output=True, text=True, timeout=10

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script fetches and analyzes recent session messages silently, which is a privacy issue because users may not expect a skill analytics tool to inspect raw conversation history. The skill context makes this more concerning because the advertised purpose is usage insight, yet the implementation relies on broader content inspection to infer behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Writing session-derived usage records to disk without an explicit warning or confirmation can create persistent local traces of user activity that the user did not knowingly authorize. Persistence raises the impact because inferred usage data may later be inspected, shared, or correlated with specific sessions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The route-type setup examples instruct users to add --lang en to recording commands, and the later HEARTBEAT template repeats English-only commands. Because this is natural-language guidance embedded in the skill and not clearly justified as region-specific, it can be read as forcing a specific language by default rather than offering an explicit opt-in choice at the point of use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This code performs a file write that can modify or replace the skill registry contents, but the only user-facing messaging is generic progress output after the fact. There is no confirmation prompt, pre-write warning comment/docstring, or explicit disclosure that existing registry data will be overwritten when updating or initializing the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script sets the output language using args.lang or i18n.detect_lang(), which means it will automatically choose a language when the user does not explicitly request one. This can violate a language/locale policy that requires user choice or opt-in rather than implicit locale detection.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script detects and logs recommendations using the Chinese phrase "建议卸载" and emits a user-facing message based on that localized output. This suggests the skill behavior depends on a fixed language/locale rather than offering a language choice or documenting a justified locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The file sets LANG_DEFAULT = "en", which causes translations to fall back to English whenever no explicit language is provided. This is a natural-language locale policy concern because the skill imposes a default language choice rather than requiring user selection or explicit opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code creates a filesystem directory via mkdir(exist_ok=True), which is a file-system modifying operation. While the function docstring notes that it will create the directory if missing, there is no user-facing confirmation, log message, or other runtime disclosure that the skill may write to the user's filesystem.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.