Back to skill

Security audit

Claw2Claude

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it grants broad automated Claude Code and cross-session messaging authority with weak scoping and several unsafe implementation choices.

Review carefully before installing. Use only in trusted, single-user OpenClaw setups and trusted project directories, and understand that delegated Claude runs without interactive permission prompts under your user account. Avoid enabling global session visibility on shared deployments, avoid sending secrets in prompts, and inspect or clear the generated logs and session files after use.

Vulnerability Patterns
  • 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
  • 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
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/launch.sh:181
Finding

Claude Code Runs Without Permission Controls or Enforced Filesystem Confinement

Content
View full analysis
&2 ;; execute) CLAUDE_ARGS+=(--dangerously-skip-permissions) echo "⚡ Execute mode (all permission prompts skipped)" >&2 # Always resume the previous session if one exists (discuss or execute) if [[ -n "$LAST_SESSION_ID" ]]; then CLAUDE_ARGS+=(--resume "$LAST_SESSION_ID") if [[ "$LAST_MODE" == "discuss" ]]; then echo "🔗 Carrying over discussion context (session: ${LAST_SESSION_ID:0:8}...)" >&2 else echo "🔗 Resuming previous execute session (${LAST_SESSION_ID:0:8}...)" >&2 fi fi ;; continue) if [[ -n "$LAST_SESSION_ID" ]]; then CLAUDE_ARGS+=(--resume "$LAST_SESSION_ID") CLAUDE_ARGS+=(--dangerously-skip-permissions) echo "🔄 Resuming ${LAST_MODE:-execute} session (${LAST_SESSION_ID:0:8}...)" >&2 else CLAUDE_ARGS+=(--dangerously-skip-permissions) echo "⚠️ No previous session found — starting a new execute session" >&2 fi ;; esac ``` The documentation simultaneously claims: ```yaml permissions: claude_flags: "--dangerously-skip-permissions" rationale: >- Required for non-interactive use. Claude Code is triggered by a chat message (not a terminal session) and cannot present permission prompts to the user. All file/tool access is bounded to the specified project directory; no system-level writes occur. ``` ### Technical Analysis The implementation disables Claude Code's interactive permission checks in every operational mode, including `discuss`, where filesystem modification and command execution are not required. Changing the process working directory to the ...[truncated 1778 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/find_session.py:43
Finding

Most-Recently-Active Session Heuristic Can Deliver Results to an Unrelated User or Channel

Content
View full analysis
/dev/null || true) if [[ -n "$DETECTED_KEY" ]]; then SESSION_KEY="$DETECTED_KEY" echo "🔑 Auto-detected session key: $SESSION_KEY" >&2 else SESSION_KEY="main" echo "⚠️ Could not detect session key — falling back to 'main'" >&2 fi ``` Results are sent using the parsed platform and target: ```python ok, resp = gateway_invoke("message", { "action": "send", "channel": platform, "target": target, "text": text, }) ``` ### Technical Analysis The destination is not bound to the authenticated session that invoked the Skill. Instead, the code reads the entire session registry and chooses whichever non-system session has the highest `updatedAt` value. This creates a race condition and a confused-deputy problem. In a multi-user or multi-channel OpenClaw deployment, another message arriving near launch time can make an unrelated session the newest candidate. The requested configuration setting `tools.sessions.visibility: "all"` broadens the accessible session scope and increases the consequences of a routing mistake. The validation in `launch.sh` checks only the shape of a supplied session key. It does not prove that the key belongs to the caller or that it was generated ...[truncated 1115 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/check_token.py:37
Finding

Automatic Credential Scanner Reads Unrelated OpenClaw Secret Files

Content
View full analysis
list[Path]: """Return all candidate credential files (.txt or .json) in the credentials directory.""" candidates = [] for f in CREDS_DIR.glob("*"): if f.suffix in (".txt", ".json") and f.is_file(): candidates.append(f) return candidates def extract_tokens(cred_file: Path) -> list[str]: """Extract token strings from a credential file.""" try: text = cred_file.read_text().strip() # JSON format: read access_token or token field if text.startswith("{"): data = json.loads(text) return [v for k, v in data.items() if k in ("access_token", "token") and isinstance(v, str)] # Plain text: treat the whole content as a token return [text] if text else [] except Exception: return [] ``` Every launch invokes the scan: ```bash # ── Check token health ─────────────────────────────────────────── python3 "$SKILL_DIR/scripts/check_token.py" || true ``` JWT payloads are decoded without authenticity verification: ```python parts = token.strip().split(".") if len(parts) != 3: return None payload_b64 = parts[1] + "=" * (-len(parts[1]) % 4) payload = json.loads(base64.urlsafe_b64decode(payload_b64)) return float(payload["exp"]) if "exp" in payload else None ``` ### Technical Analysis The scanner reads every top-level `.txt` and `.json` file under `~/.openclaw/credentials`, including credentials unrelated to Claude or the active task. Plain-text files are read in full and treated as possible tokens. This behavior is not required to delegate work to Claude. It is only a warning mechanism, always exits successfully, and cannot refresh ...[truncated 1503 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/launch.sh:258
Finding

Attacker-Controlled Project Files Enable Arbitrary Same-User Process Termination and Symlink File Overwrites

Content
View full analysis
/dev/null; then echo ".openclaw-claude-session.json" >> .gitignore fi ``` It trusts a PID read from the selected project: ```bash NOTIFIER_PID_PERSIST="${PROJECT_PATH}/.claude-notifier.pid" if [[ -f "$NOTIFIER_PID_PERSIST" ]]; then STALE_PID=$(cat "$NOTIFIER_PID_PERSIST" 2>/dev/null || true) if [[ -n "$STALE_PID" ]]; then kill "$STALE_PID" 2>/dev/null && echo "🧹 Killed stale notifier (PID=$STALE_PID)" >&2 || true fi rm -f "$NOTIFIER_PID_PERSIST" fi ``` Project-local log files are opened or redirected without no-follow protection: ```bash NOTIFIER_LOG="${PROJECT_PATH}/.claude-notifier.log" nohup python3 "$SKILL_DIR/scripts/notifier.py" \ --notify-file "$NOTIFY_FILE" \ --project "$PROJECT_NAME" \ --session-key "$SESSION_KEY" \ --watcher-pid $$ \ --max-wait $((TIMEOUT_SEC + 120)) \ > "$NOTIFIER_LOG" 2>&1 & ``` ```python if args.log_out: try: log_file = open(args.log_out, "w", encoding="utf-8") log_file.write(HEADER + "\n") except OSError as e: print(f"⚠️ Could not open log file: {e}", file=sys.stderr) ``` ### Technical Analysis The selected project may be an attacker-controlled repository. Files inside it must therefore be treated as untrusted. The PID cleanup logic accepts any non-empty value from `.claude-notifier.pid` and sends a signal to it. It does not verify that the value is numeric, that the process belongs to this Skill, that its executable is `notifier.py`, or that it was started for the current project. If the attacker supplies the PID of another ...[truncated 1790 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/launch.sh:27
Finding

Persistent Logs Retain Prompt Content, Session Identifiers, Paths, and Full Claude Output Without Explicit Protection

Content
View full analysis
[] local status="${1:-}" local claude_session="${2:-}" python3 "$SKILL_DIR/scripts/log_entry.py" \ --log-file "$LOG_FILE" \ --status "$status" \ --project "$PROJECT_PATH" \ --mode "$MODE" \ --session-key "$SESSION_KEY" \ --claude-session "$claude_session" \ --prompt "${PROMPT:0:200}" \ 2>/dev/null || true } ``` The logger writes those fields without redaction: ```python entry = { "ts": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), "status": args.status, "project": args.project, "mode": args.mode, "session_key": args.session_key, "claude_session": args.claude_session[:8] if args.claude_session else "", "prompt": args.prompt, } log_path = Path(args.log_file) log_path.parent.mkdir(parents=True, exist_ok=True) with open(log_path, "a", encoding="utf-8") as f: f.write(json.dumps(entry, ensure_ascii=False) + "\n") ``` The complete Claude response is also retained: ```python if args.log_out: try: log_file = open(args.log_out, "w", encoding="utf-8") log_file.write(HEADER + "\n") except OSError as e: print(f"⚠️ Could not open log file: {e}", file=sys.stderr) ``` ### Technical Analysis The first 200 characters of a prompt may contain passwords, tokens, customer data, internal URLs, or other confidential information. The monthly log also records absolute project paths, channel/session keys, and shorten ...[truncated 1519 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/heartbeat.py:49
Finding

Background Heartbeat Sends Unstructured Execution Log Content and Duplicates Completion Delivery

Content
View full analysis
str: """Extract the most useful content from the log tail, capped at max_chars.""" lines = log_tail.splitlines() # Prefer content around the ✅ completion marker for i, line in enumerate(lines): if "✅" in line and ("complete" in line.lower() or "Claude Code" in line): snippet = "\n".join(lines[max(0, i - 2):i + 25]) return snippet[:max_chars] # No completion marker found — return the last 35 lines tail = "\n".join(lines[-35:]) return tail[:max_chars] ``` It embeds that content into a session message: ```python log_tail = read_log_tail(args.log) summary = extract_summary(log_tail) inject_message = ( f"[Background task complete] Claude Code has finished working on **{args.project}**.\n\n" f"Summary:\n{summary}\n\n" f"(This message was pushed automatically by the heartbeat process.)" ) _gw = load_gateway_config(args.config) gw_url = args.gateway_url or _gw[0] gw_token = args.gateway_token or _gw[1] notified = sessions_send(gw_url, gw_token, args.session_key, inject_message) ``` Background mode starts this additional monitor: ```bash nohup python3 "$SKILL_DIR/scripts/heartbeat.py" \ --pid "$BG_PID" \ --log "$BG_LOG" \ --project "$PROJECT_NAME" \ --session-key "$SESSION_KEY" \ > "${BG_LOG%.log}-heartbeat.log" 2>&1 & ``` ### Technical Analysis Background mode launches a nested `execute` invocation, and that invocation already starts `notifier.py` to deliver the structured completion summary. The outer heartbeat creates a second delivery path. Unlike the notifier, the h ...[truncated 1704 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill can send outbound messages through a gateway across sessions and reportedly uses additional authenticated channels such as Discord-related credentials and local notifications. Any component with token-backed messaging authority plus auto-routing can exfiltrate task content or send to unintended recipients if session resolution or gateway handling is flawed.

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

md
The registry is printed to stderr automatically each time `launch.sh` runs — you do not need a separate call unless you need to inspect it *before* deciding whi

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
The registry is printed to stderr automatically each time `launch.sh` runs — you do not need a separate call unless you need to inspect it *before* deciding whi

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script performs credential discovery and token inspection under ~/.openclaw/credentials even though the skill is described as a Claude Code delegation tool. This mismatch expands the skill's effective privilege and can expose sensitive authentication metadata, creating a clear overreach beyond the declared purpose and increasing the chance of unintended credential access or misuse.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The launcher routinely passes --dangerously-skip-permissions in discuss, execute, and continue flows, disabling a key safety control around code execution and file/system access. This is especially dangerous here because the skill is designed to activate quickly and can also resume prior sessions, allowing Claude to act on prompts and existing context with reduced friction and minimal user visibility.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The documentation describes launching Claude in a project directory where it can read and write files and execute code, but it does not prominently warn users about that level of local access or the persistence of session state files. In a delegation skill, missing disclosure can lead users to invoke the tool without informed consent about filesystem modification and local data handling.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README explicitly instructs operators to enable the gateway message tool for external callers and set session visibility to all, which broadens privileges well beyond simple local Claude delegation. This weakens isolation between sessions and allows a background process to send messages into arbitrary user conversations, creating a real risk of cross-session data exposure, spoofed responses, or abuse if the notifier or host is compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README tells users to disable normal session visibility protections so a detached notifier can message across session boundaries, but it does not clearly warn that this changes privacy and trust assumptions for all sessions. Users may enable the setting without understanding that outputs from one task could be exposed or misrouted into another user's conversation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares powerful capabilities including reading OpenClaw config and credentials, writing logs and session files, invoking shell commands, and sending messages via a gateway, but it does not provide a formal restrictive tool scope such as explicit allowed-tools/permissions. In practice this means the effective authority is broad and underconstrained, which raises the risk of unintended file access, data exposure, or command execution beyond what users expect from a delegation skill.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

The skill promotes persistent project/session creation for a wide range of code and non-code tasks and stores session state plus logs on disk. Persistent storage increases privacy and confidentiality risk because prompts, metadata, and task context may remain available after the task ends, especially when combined with cross-session messaging and background processes.

Content

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

md
---
name: claw2claude
description: "Delegates tasks to the local Claude Code CLI. Activate immediately when the user asks for Claude, requests a stronger model, or mentions an existing project path. Ask the user first whether to create a Claude project when: the task involves building something from scratch, spans multiple parts, requires multiple rounds of iteration, or the user is expressing a direction rather than a concrete single question. Applies to code AND non-code work (business plans, product specs, docs, etc.). Do not start answering directly — ask first."
license: MIT
metadata:
  openclaw:

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation conditions are extremely broad, including generic phrases like asking for a stronger model or mentioning an existing project path. In context, that can cause accidental invocation of a high-privilege delegation workflow, escalating ordinary chat requests into shell execution, file writes, session persistence, and background processing without sufficiently explicit user intent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code enumerates local credential files and parses token contents, which is sensitive file access unrelated to the stated purpose of delegating work to the local Claude CLI. Even though it does not exfiltrate secrets, reading and decoding local credentials violates least privilege and could normalize unsafe access patterns or be repurposed to leak or misuse authentication data later.

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/heartbeat.py (reported line 134)May include surrounding context.

python
safe_title = title.replace('"', "'")
        safe_body  = body[:200].replace('"', "'").replace("\n", " ")
        script = f'display notification "{safe_body}" with title "{safe_title}" sound name "Glass"'
        subprocess.run(["osascript", "-e", script], check=False, timeout=5)
        print("[heartbeat] 🔔 macOS notification sent", flush=True)
    except Exception as e:
        print(f"[heartbeat] ⚠️  macOS notification failed: {e}", flush=True)

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/notifier.py (reported line 170)May include surrounding context.

python
safe_title = title.replace('"', "'")
        safe_body  = body[:200].replace('"', "'").replace("\n", " ")
        script = f'display notification "{safe_body}" with title "{safe_title}" sound name "Glass"'
        subprocess.run(["osascript", "-e", script], check=False, timeout=5)
        print("[heartbeat] 🔔 macOS notification sent", flush=True)
    except Exception as e:
        print(f"[heartbeat] ⚠️  macOS notification failed: {e}", flush=True)

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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/launch.sh (reported line 70)May include surrounding context.

sh
# ── Cleanup on exit ──────────────────────────────────────────────
NOTIFIER_PID_FILE=""
cleanup() {
  # Do NOT kill the notifier here — it is a nohup background process that must
  # outlive launch.sh to deliver results after Claude finishes.
  # Only clean up temp files.
  rm -rf "$TMPDIR_BASE"

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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/launch.sh (reported line 160)May include surrounding context.

sh
# ── Cleanup on exit ──────────────────────────────────────────────
NOTIFIER_PID_FILE=""
cleanup() {
  # Do NOT kill the notifier here — it is a nohup background process that must
  # outlive launch.sh to deliver results after Claude finishes.
  # Only clean up temp files.
  rm -rf "$TMPDIR_BASE"