Back to skill

Security audit

claude-code-bridge

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-coherent, but needs review because it exposes a chat-controlled persistent local Claude Code terminal and has a confirmed startup command-injection risk.

Install only if you intentionally want chat users on those channels to control a local Claude Code terminal. Use sandbox mode or a low-privilege account, avoid sensitive directories, restrict who can message the bot, avoid project-wide approvals unless you understand the requested action, and treat /cc peek/history output as potentially sensitive. The startup command-injection and session-collision issues should be fixed before use in shared, remote, or multi-user environments.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/claude-code-bridge.sh:136
Finding
Shell Command Injection Through the Working Directory Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/claude-code-bridge.sh`, lines 136–172 **Vulnerability Type**: Shell command injection through unsafe command-string construction **Risk Level**: High ### Vulnerable Code ```bash local workdir="${MESSAGE:-}" local is_sandbox=0 if [[ "$workdir" == "--sandbox" || -z "$workdir" ]]; then # Sandbox mode: create a temporary directory workdir=$(mktemp -d /tmp/cc-sandbox-XXXXXX) is_sandbox=1 echo "$workdir" > "$SANDBOX_FLAG" else # Expand ~ to $HOME workdir="${workdir/#\~/$HOME}" fi # Verify that the directory exists if [[ ! -d "$workdir" ]]; then echo "[claude-code-bridge] ❌ Directory does not exist: $workdir" rm -f "$SANDBOX_FLAG" return 1 fi # Record the working directory echo "$workdir" > "$WORKDIR_FILE" # Build startup command local launch_cmd launch_cmd="cd '$workdir' && unset CLAUDECODE CLAUDE_CODE; export TERM=xterm-256color; exec '$CLAUDE_BIN'" # Start Claude inside tmux tmux new-session -d -s "$TMUX_NAME" -x 220 -y 50 "bash --login -c '$launch_cmd'" ``` ### Technical Analysis The working directory is derived from the third command-line argument, which the Skill instructions populate from a path supplied through a chat message. Although the script verifies that the path identifies an existing directory, it later interpolates that value into a shell command using manually constructed single quotes. A single quote inside the directory name can terminate the intended quoting context. Subsequent shell metacharacters in that directory name can then become executable shell syntax when the generated string is evaluated by `bash --login -c`. There are two nested levels of shell command interpretation: 1. `launch_cmd` embeds `workdir` and `CLAUDE_BIN` in a command string. 2. That command string is embedded again in the argument passed to `bash --login -c`. The directory existence check does not prevent exploitation because Unix file names may legally contain qu ...[truncated 2019 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid composing shell source code from input values. 1. Use tmux's working-directory option to pass the directory as a distinct argument rather than embedding it in `cd`: ```bash tmux new-session -d \ -s "$TMUX_NAME" \ -c "$workdir" \ -x 220 -y 50 \ "env -u CLAUDECODE -u CLAUDE_CODE TERM=xterm-256color \"$CLAUDE_BIN\"" ``` 2. Prefer launching a small fixed wrapper script when tmux requires a command string. Pass the working directory and executable as positional arguments to the wrapper instead of interpolating them into shell code. 3. If string construction cannot be eliminated, apply shell-safe escaping to every interpolated value with `printf '%q'`. Escaping must account for both nested evaluation layers. 4. Resolve and validate the working directory with a canonicalization mechanism such as `realpath` where supported. 5. Validate that `CLAUDE_BIN` is an absolute path to an expected executable and reject unexpected values. 6. Add regression tests using valid directories containing single quotes, semicolons, spaces, dollar signs, and command-substitution characters. Confirm that no additional command is executed. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/claude-code-bridge.sh:42
Finding
Cross-Chat Session Access Through Colliding Session Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/claude-code-bridge.sh`, lines 42–47 **Vulnerability Type**: Session identifier collision and insufficient authorization isolation **Risk Level**: Medium ### Vulnerable Code ```bash # Convert an arbitrary session_id to a legal tmux name SAFE_ID="$(echo "$SESSION_ID" | tr -cd '[:alnum:]_' | cut -c1-20)" TMUX_NAME="ccb_${SAFE_ID}" LOG_FILE="$STATE_DIR/${TMUX_NAME}.log" OFFSET_FILE="$STATE_DIR/${TMUX_NAME}.offset" WORKDIR_FILE="$STATE_DIR/${TMUX_NAME}.workdir" SANDBOX_FLAG="$STATE_DIR/${TMUX_NAME}.sandbox" ``` ### Technical Analysis The complete channel and chat identifier is converted to a tmux identifier by: 1. Removing every character outside the alphanumeric and underscore character set. 2. Truncating the resulting value to 20 characters. This transformation is not injective. Multiple distinct identifiers can produce the same `SAFE_ID`. Examples include identifiers that differ only by removed punctuation and identifiers that share the same first 20 retained characters. Every security-relevant resource is then derived solely from the colliding value: - The tmux session name. - The terminal transcript file. - The output offset file. - The working-directory state file. - The sandbox marker. The script neither stores the complete original identifier nor verifies that a caller owns the existing tmux session before executing `send`, `approve`, `peek`, `history`, `restart`, or `stop`. The Skill documentation instructs the caller to construct identifiers with only letters, digits, and underscores, which reduces punctuation-based collisions but does not prevent truncation collisions. The script itself also accepts arbitrary identifiers and silently normalizes them. ### Attack Path 1. A victim starts a Claude Code session using a channel/chat identifier whose normalized prefix is known or predictable. 2. An attacker operates from a distinct chat whose identifier normalizes to the same first 20 char ...[truncated 1743 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Derive resource names from a collision-resistant digest of the complete, unmodified identifier: ```bash SESSION_HASH="$(printf '%s' "$SESSION_ID" | sha256sum | awk '{print $1}')" SAFE_ID="${SESSION_HASH:0:32}" TMUX_NAME="ccb_${SAFE_ID}" ``` Use the platform-appropriate hashing tool on macOS if necessary. 2. Include a readable sanitized prefix only for diagnostics; do not rely on it for uniqueness: ```bash PREFIX="$(printf '%s' "$SESSION_ID" | tr -cd '[:alnum:]_' | cut -c1-8)" TMUX_NAME="ccb_${PREFIX}_${SESSION_HASH:0:24}" ``` 3. Store the complete original session identifier in a mode-`0600` ownership file when creating a session. 4. Before every action, compare the supplied complete identifier with the stored identifier and reject mismatches. 5. Reject identifiers that normalize to an empty value. 6. Add tests for: - Identifiers longer than 20 characters with identical prefixes. - Identifiers differing only in punctuation. - Empty normalized identifiers. - Concurrent sessions from different channels with similar chat IDs. 7. Where possible, include an authenticated, server-generated channel namespace rather than trusting a display name or user-controlled identifier. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/claude-code-bridge.sh:31
Finding
Sensitive Claude Code Transcripts Stored Without Enforced Private Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/claude-code-bridge.sh`, lines 31–47, 158–162, and 177 **Vulnerability Type**: Insecure permissions for sensitive local state and terminal transcripts **Risk Level**: Low ### Vulnerable Code ```bash STATE_DIR="$HOME/.openclaw/claude-code-bridge" SCROLLBACK_LINES=50000 STABLE_INTERVAL=0.8 STABLE_NEEDED=3 DEFAULT_TIMEOUT=90 LONG_TIMEOUT=300 mkdir -p "$STATE_DIR" SAFE_ID="$(echo "$SESSION_ID" | tr -cd '[:alnum:]_' | cut -c1-20)" TMUX_NAME="ccb_${SAFE_ID}" LOG_FILE="$STATE_DIR/${TMUX_NAME}.log" OFFSET_FILE="$STATE_DIR/${TMUX_NAME}.offset" WORKDIR_FILE="$STATE_DIR/${TMUX_NAME}.workdir" SANDBOX_FLAG="$STATE_DIR/${TMUX_NAME}.sandbox" ``` The state files and transcript are subsequently created or written without explicit permission controls: ```bash # Record the working directory echo "$workdir" > "$WORKDIR_FILE" # Clear old log > "$LOG_FILE" echo "0" > "$OFFSET_FILE" ``` ```bash tmux pipe-pane -t "$TMUX_NAME" -o "cat >> '$LOG_FILE'" ``` ### Technical Analysis The script creates a state directory and several files without setting a restrictive `umask` or explicitly applying secure modes. The effective permissions therefore depend on the environment inherited by the script. Under a common `umask` of `022`: - Newly created directories are commonly mode `0755`. - Newly created regular files are commonly mode `0644`. This can allow other local users to traverse the state directory and read terminal transcripts or metadata. The transcript is generated by `tmux pipe-pane` and may contain source code, command output, file contents, error messages, tokens printed by tools, or other sensitive project information. The working-directory file also discloses project locations. The sandbox marker identifies temporary directories, while the output offset reveals less sensitive operational state. Although `do_stop` removes these files, they remain present for the lifetime of the session and may persist if the p ...[truncated 1341 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set a restrictive umask before creating any state: ```bash umask 077 ``` 2. Create and repair the state directory with owner-only permissions: ```bash mkdir -p -m 700 "$STATE_DIR" chmod 700 "$STATE_DIR" ``` 3. Create transcript and metadata files with mode `0600`. Apply `chmod 600` to existing files before appending. 4. Use secure file-creation techniques that prevent following attacker-created symbolic links. For example, verify the state directory is owner-controlled and reject unexpected non-regular state files. 5. Consider placing runtime logs under an owner-private runtime directory such as `$XDG_RUNTIME_DIR` when available. 6. Minimize transcript retention. Disable persistent `pipe-pane` logging if file-size polling can be replaced with tmux state inspection, or truncate and remove logs promptly. 7. Install signal and exit traps to remove transient state after abnormal termination where doing so will not interfere with intentional persistence. 8. Document that terminal output may contain secrets and recommend avoiding the display of credentials in Claude Code sessions. ]]>
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README explicitly advertises that the skill exposes a real interactive terminal over chat and supports command execution, file writes, and Git operations, but it does not prominently warn users about the security consequences of granting remote chat-originated access to a persistent local CLI session. This is dangerous because operators may deploy it without understanding that any compromise of the chat account, channel, bot routing, or authorization logic could translate into local code execution and data modification on the host.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill explicitly routes every incoming message to a persistent Claude Code session whenever CC mode is active, but the documentation does not clearly warn users that ordinary chat messages will be forwarded into that live CLI context. This creates a serious risk of unintended command execution, sensitive data exposure, and confusion about when the user is talking to OpenClaw versus controlling an active coding agent, especially across messaging platforms where users may casually send unrelated content.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The startup flow allows launching Claude Code in a user-specified working directory, including paths like home or project directories, without clearly warning that the connected agent may read, modify, or delete files there. In this skill's context, that omission is especially dangerous because the bridge connects remote chat input to a persistent CLI agent, so a mistaken or socially engineered directory choice could expose sensitive local data or permit destructive file operations.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The approval-flow section explains how to translate user responses into approval choices, but it does not clearly warn that approving a prompt may authorize impactful tool actions such as running commands, modifying files, or accessing sensitive project resources. Because approvals are being relayed through chat rather than a local interactive terminal, users may approve actions with reduced context, making accidental over-authorization more likely.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The guide explicitly tells users that Claude Code may request approval for command execution and file read/write operations, but it does not clearly warn that approving these actions can expose sensitive data, modify important files, or execute harmful commands on the host system. In this skill’s context, that omission is more dangerous because all chat messages in CC mode are forwarded into a persistent CLI session, increasing the chance that a user casually approves risky actions from a messaging interface without full situational awareness.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
Comments and user-visible status/error strings throughout the script are written in Chinese, and there is no mechanism to select another language or opt in to this locale. This can violate language/locale policy where tools must not force a specific language on users without choice or clear justification.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script exposes `interrupt` and especially `key` actions that let a chat-originated request inject control keys directly into the tmux-backed Claude Code session. In this skill context, the bridge is reachable from messaging channels and is meant to proxy natural-language interaction plus approval handling, so arbitrary key injection materially expands the attack surface by allowing out-of-band control of the terminal UI and approval flows beyond the declared purpose.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# 解析工作目录参数
    local workdir="${MESSAGE:-}"
    local is_sandbox=0

    if [[ "$workdir" == "--sandbox" || -z "$workdir" ]]; then
        # 沙盒模式:创建临时目录
Confidence
88% confidence
Finding
The script defaults to using the caller-supplied or current working directory and only enters sandbox mode when `--sandbox` is explicitly requested or no directory is provided. For a chat-triggered bridge to a powerful coding agent, making non-sandbox execution the default increases the chance that untrusted or accidental prompts operate directly on real user files and repositories.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script pipes the full tmux pane output into a persistent log file under `~/.openclaw/claude-code-bridge` without notifying the user that Claude responses and terminal content are being retained. In a chat-bridge context, that output may include secrets, file contents, prompts, tokens, or sensitive operational data, creating avoidable local data exposure and retention risk.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The `peek` and `history` actions expose captured terminal content back through the chat interface, which can surface secrets or private data present in the Claude Code session. In this multi-channel messaging context, that is especially risky because anyone with access to the chat control path may retrieve prior terminal output that was not intended to be re-shared.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
`do_key()` accepts a broad set of navigation and control sequences (`ctrl+*`, `alt+*`, arrows, tab, escape) and forwards them to the live Claude Code terminal. Because this skill bridges remote chat platforms to a persistent interactive session, that capability can be abused to manipulate the TUI, alter prompts, confirm actions, interrupt safeguards, or access interface states that simple message forwarding would not expose.

Static analysis

No suspicious patterns detected.