Back to skill

Security audit

OpenCode ACP Control v2

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its OpenCode automation purpose, but it gives agents unsafe cleanup and generated-command workflows that can affect unrelated local sessions.

Review this skill carefully before installing. It can help automate OpenCode ACP sessions, but its cleanup logic can remove lock files for unrelated OpenClaw sessions, and its helper script outputs executable steps built from unescaped user-supplied values. Use only in an isolated environment or after revising cleanup to target the exact current session and treating generated workflow text as untrusted data.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
opencode-session.sh:344
Finding

Unescaped User Input in Agent-Executable Workflow Output

Content
View full analysis

Vulnerability Details

File Location: opencode-session.sh, lines 344-358
Vulnerability Type: Command and JSON-RPC instruction injection
Risk Level: High

Vulnerable Code

bash
## Step 1: Start OpenCode
exec(command: "opencode acp --cwd $project", background: true, workdir: "$project")
# → Save returned sessionId as PROCESS_SESSION_ID

## Step 2: Initialize
process.write(PROCESS_SESSION_ID, data: '$(initialize_opencode)' + "\\n")
process.poll(PROCESS_SESSION_ID, timeout: $TIMEOUT_INIT)
# → Expect: {"result":{"protocolVersion":1,...}}

## Step 3: Create Session
process.write(PROCESS_SESSION_ID, data: '$(create_session "$project" "$mcp_servers")' + "\\n")
process.poll(PROCESS_SESSION_ID, timeout: $TIMEOUT_SESSION)
# → Save result.sessionId as OPENCODE_SESSION_ID

## Step 4: Send Prompt
process.write(PROCESS_SESSION_ID, data: '$(send_prompt "OPENCODE_SESSION_ID" "$prompt")' + "\\n")

The underlying JSON-RPC construction also directly interpolates these values:

bash
create_session() {
    local cwd="$1"
    local mcp_servers="$2"

    log INFO "Creating session in $cwd"

    local params="{\"cwd\":\"${cwd}\",\"mcpServers\":${mcp_servers:-[]}}"
    local json=$(send_jsonrpc "session/new" "$params")

    echo "$json"
}

send_prompt() {
    local session_id="$1"
    local prompt="$2"

    log INFO "Sending prompt (${#prompt} chars)"

    local params="{\"sessionId\":\"${session_id}\",\"prompt\":[{\"type\":\"text\",\"text\":\"${prompt}\"}]}"
    local json=$(send_jsonrpc "session/prompt" "$params")

    echo "$json"
}

Technical Analysis

Values supplied through --project, --prompt, and --mcp are inserted into generated command syntax and JSON-RPC messages without context-appropriate escaping or validation.

The script does not directly execute the generated workflow. However, its documentation explicitly instructs CYPHER or another consuming age ...[truncated 1919 chars]

Remediation
View remediation

Remediation Suggestions

  1. Stop producing executable command syntax through string interpolation. Return a structured data document whose fields remain data rather than instructions.

  2. Construct all JSON-RPC messages with a real JSON serializer, such as:

    bash
    jq -cn \
      --arg cwd "$cwd" \
      --argjson mcpServers "$mcp_servers" \
      '{jsonrpc:"2.0", id:1, method:"session/new",
        params:{cwd:$cwd, mcpServers:$mcpServers}}'
    
  3. Construct prompt messages with jq --arg prompt "$prompt" so quotation marks, newlines, backslashes, and control characters are escaped correctly.

  4. Validate MCP input before use:

    bash
    jq -e 'type == "array" and all(.[]; type == "string")' \
      <<< "$mcp_servers" >/dev/null
    
  5. Canonicalize the project path with realpath, require it to be an existing directory, and optionally restrict it to approved workspace roots.

  6. Invoke processes through structured argument arrays rather than a generated shell command string.

  7. Ensure the downstream agent treats script output as untrusted data. It should execute only a fixed, locally defined workflow and populate validated parameters into that workflow.

  8. Add regression tests covering embedded quotation marks, newlines, backslashes, JSON delimiters, and strings resembling agent tool calls.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
opencode-session.sh:63
Finding

Global Deletion of Session Locks Across Unrelated OpenClaw Agents

Content
View full analysis

Vulnerability Details

File Location: opencode-session.sh, lines 63-76 and line 371; also documented repeatedly in SKILL.md
Vulnerability Type: Overbroad lock-file deletion and violation of least privilege
Risk Level: Medium

Vulnerable Code

bash
cleanup_stale_locks() {
    log INFO "Cleaning stale locks (>30min old)"
    find ~/.openclaw/agents -name '*.lock' -mmin +30 -delete 2>/dev/null || true
}

cleanup_session() {
    if [[ -n "$PROCESS_SESSION_ID" ]]; then
        log INFO "Cleaning up session"
        # Kill process would be done by caller via process.kill
        # Just clean locks here
        rm -f ~/.openclaw/agents/*/sessions/*.lock 2>/dev/null || true
    fi
}

The generated cleanup workflow contains the same unrestricted deletion:

bash
## Step 6: Cleanup
process.kill(PROCESS_SESSION_ID)
exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock")

The behavior is also recommended in SKILL.md, including:

bash
exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock")

Technical Analysis

The wildcard cleanup is not scoped to the OpenCode process or session created by this Skill. It targets lock files belonging to every agent beneath ~/.openclaw/agents/*/sessions/.

The find command applies an age check, but it still operates across all agents and does not verify whether the process associated with a lock remains alive. The rm command is more dangerous because it removes every matching lock regardless of age, ownership by the current workflow, or session activity.

Lock files enforce coordination between processes. Removing a valid lock does not directly grant additional operating-system permissions, but it can bypass application-level mutual exclusion and allow multiple processes to act on state that should have remained exclusively locked.

Attack Path

  1. One or more unrelated OpenClaw agents have active sessions and c ...[truncated 1151 chars]
Remediation
View remediation

Remediation Suggestions

  1. Record the exact lock path associated with the process and OpenCode session created by this Skill.
  2. Remove only that specific lock during cleanup; do not use wildcards spanning all agents.
  3. Before deleting a lock, verify:
    • The lock belongs to the expected session.
    • The recorded process identifier is no longer alive.
    • The lock path resolves beneath the expected session directory.
    • The file is a regular file and not a symbolic link.
  4. If stale-lock recovery is required, use session-specific metadata and an atomic ownership check rather than age alone.
  5. Replace the generated cleanup command with a fixed helper that receives a validated session identifier and computes the permitted lock path internally.
  6. Refuse suspicious session identifiers containing path separators or traversal sequences.
  7. Log every deleted lock with its session identifier and the evidence used to determine that it was stale.
  8. Update SKILL.md to remove all recommendations for global wildcard lock deletion.
  9. Add concurrency tests proving that cleanup of one OpenCode session cannot remove or modify locks belonging to another agent.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (22)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The skill explicitly directs use of a destructive shell command, rm -f ~/.openclaw/agents//sessions/.lock, via exec. Allowing an agent to issue deletion commands with globbing in the user's home directory is dangerous because mistakes, environment differences, or malicious influence over execution context can cause unintended data loss or normalize unsafe command execution patterns.

Content

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

md
| Read response | `process.poll(sessionId)` - adaptive polling |
| Health check | `process.poll(sessionId, timeout: 5000)` - only when no output >60s |
| Stop OpenCode | `process.kill(sessionId)` + cleanup locks |
| Clean locks | `exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock")` |
| List sessions | `exec(command: "opencode session list", workdir: "...")` |
| Resume session | List sessions → `session/load` |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `SKILL.md` | This file - main documentation |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This recovery step again recommends direct execution of rm -f against a glob in ~/.openclaw after killing a process. Embedding destructive shell parameters in automated recovery magnifies risk because the action may happen repeatedly without review and can be triggered by false stuck detection.

Content

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

exec(command: "find ~/.openclaw/agents -name '*.lock' -mmin +30 -delete")

After killing a stuck process

exec(command: "rm -f ~/.openclaw/agents//sessions/.lock")

text

---

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The documented final cleanup instructs an agent to kill a process and then run rm -f on a home-directory glob. Combining process control and file deletion in a routine completion path creates a strong chance of accidental destructive behavior and exceeds what many users would expect from a protocol helper.

Content

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

text
process.kill(sessionId)
exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
94% confidence
Finding

The recovery function hardcodes a destructive exec("rm -f ~/.openclaw/agents//sessions/.lock") step, making filesystem deletion part of automated error handling. Automated destructive commands are especially risky because they may be reached during normal faults, retries, or misclassification of process state, leading to repeated unintended deletions.

Content

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

md
process.kill(sessionId)
    
    # Step 4: Clean up
    exec("rm -f ~/.openclaw/agents/*/sessions/*.lock")
    
    # Step 5: Restart
    newSessionId = startOpenCode()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The cleanup function deletes all matching session lock files under ~/.openclaw/agents/*/sessions using a wildcard rather than targeting locks associated with the current session. This can interfere with other active sessions, break synchronization guarantees, and potentially enable concurrent operations against resources that were protected by those locks.

Content

Scanner excerpt · opencode-session.sh (reported line 74)May include surrounding context.

sh
log INFO "Cleaning up session"
        # Kill process would be done by caller via process.kill
        # Just clean locks here
        rm -f ~/.openclaw/agents/*/sessions/*.lock 2>/dev/null || true
    fi
}

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The script emits workflow instructions that direct downstream execution of a destructive shell command deleting all session lock files. Because this is packaged as part of an automation skill, it increases the chance that callers will execute the command blindly, causing cross-session disruption or corruption in environments where multiple agents or users rely on those locks.

Content

Scanner excerpt · opencode-session.sh (reported line 371)May include surrounding context.

sh
## Step 6: Cleanup
process.kill(PROCESS_SESSION_ID)
exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock")

# Metrics to log:
# - duration_ms

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
77% confidence
Finding

The skill documents substantial capabilities including ACP session control, shell execution, filesystem deletion, and MCP server usage, but the manifest does not declare any explicit tool scope or permissions. That mismatch increases the chance an agent will invoke broader tools than users expect, weakening least-privilege controls and informed consent.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
|---------|-------------|
| **Auto-retry** | Automatically retries on failure (max 3 attempts) |
| **Stuck detection** | Detects when OpenCode is not responding |
| **Lock cleanup** | Automatically removes stale lock files |
| **Adaptive polling** | Polls faster at start, slower when stable |
| **Health checks** | Periodic checks that OpenCode is alive |
| **Configurable timeouts** | Shorter timeouts with escalation |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documented command uses rm -f on lock files under ~/.openclaw without an explicit warning that it deletes files in the user's home directory. Even with a seemingly narrow glob, destructive commands can remove files unexpectedly or normalize risky deletion behavior in agents.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill recommends shell commands for file deletion and maintenance actions that go beyond narrow ACP control, effectively encouraging arbitrary command execution. Expanding from protocol interaction to unrestricted shell use raises the risk of destructive actions, path mistakes, and abuse if prompts or variables are influenced by untrusted input.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Automatic stale-lock deletion is described as routine behavior but lacks a clear warning that it mutates the filesystem. Silent deletion in recovery flows is risky because agents may perform it repeatedly and users may not realize home-directory files are being removed.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 · SKILL.md (reported line 217)May include surrounding context.

restart from Step 2

text

### Step 4: Create Session (with retry)

```json
{"jsonrpc":"2.0","id":1,"method":"session/new","params":{"cwd":"/path/to/project","mcpServers":[]}}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The cleanup sequence combines process termination with lock-file deletion but does not present safety guidance or validation steps. This can lead to abrupt state loss and unnecessary file removal if triggered during normal operation or against the wrong session.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 · SKILL.md (reported line 469)May include surrounding context.

md
if attempt == 3:
    throw Error("Failed to initialize after 3 attempts")

# Create session with retry
for attempt in 1..3:
  process.write(state.processSessionId, session_new())
  response = process.poll(state.processSessionId, timeout: 10000)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 · opencode-session.sh (reported line 352)May include surrounding context.

sh
process.poll(PROCESS_SESSION_ID, timeout: $TIMEOUT_INIT)
# → Expect: {"result":{"protocolVersion":1,...}}

## Step 3: Create Session
process.write(PROCESS_SESSION_ID, data: '$(create_session "$project" "$mcp_servers")' + "\\n")
process.poll(PROCESS_SESSION_ID, timeout: $TIMEOUT_SESSION)
# → Save result.sessionId as OPENCODE_SESSION_ID

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The generated workflow tells the caller to run a broad lock-file deletion command against all matching session locks without confirming ownership, scope, or whether the lock is still needed. In a shared or multi-session environment, this can disrupt unrelated agent sessions and cause denial of service or unsafe concurrent access.

Content

No source excerpt is available for this finding.

Indirect Prompt Extraction

Medium
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains patterns that could indirectly extract system prompts through rephrasing, translation, summarization, or side-channel techniques.

Content

Scanner excerpt · templates.md (reported line 1)May include surrounding context.

md
# OpenCode Prompt Templates

Templates para tareas comunes de código.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest says the skill controls OpenCode via ACP, but the quick reference also includes direct deletion of lock files in the user's home directory. This scope expansion is security-relevant because operators may not expect filesystem mutation from a protocol-control skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The documentation introduces an external helper shell script that orchestrates execution, but that capability is not reflected in the manifest. Hidden operational scope makes it easier for downstream agents or users to trust the skill for ACP-only behavior while it actually drives shell-based automation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The documentation says the helper script can perform a dry run, but then instructs the agent to execute emitted steps in order. That contradiction can mislead operators into thinking a non-executing preview is safer than it is, increasing the chance of accidental command execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This markdown file contains user-facing guidance in Spanish while the reusable prompt templates themselves are consistently written in English. Because the skill does not state that English is required or give the user a language/locale choice, it effectively steers usage toward a specific language without explicit opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.