Back to skill

Security audit

Dispatch (Claude Code)

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a local Claude Code dispatcher, but it gives background agents more control than the user-facing description makes clear.

Install only if you control the callers and runtime environment. Use strict allowlisted project and task names, avoid bypassPermissions, keep results/log directories private, and do not send sensitive prompts unless local plaintext storage is acceptable. This does not appear intentionally malicious, but it deserves review before use because it can run long-lived local agents and approve Claude safety prompts automatically.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/run_dispatch.sh:73
Finding
Path Traversal Through Unvalidated Project and Task Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_dispatch.sh:73-92` **Vulnerability Type**: Path traversal and unrestricted filesystem path construction **Risk Level**: High ### Vulnerable Code ```bash PROJECT="$1" TASK_NAME="$2" shift 2 PROMPT="$*" WORKDIR="${REPOS_ROOT}/${PROJECT}" mkdir -p "$WORKDIR" "$LAUNCH_LOG_DIR" NEED_TEAMS=0 if echo "$PROMPT" | grep -Eiq '(Agent Team|Agent Teams|多智能体|并行|testing agent)'; then NEED_TEAMS=1 fi RUN_ID="$(date -u +%Y%m%d-%H%M%S)-${PROJECT}-${TASK_NAME}" RESULT_DIR="$RESULTS_BASE/$PROJECT/$RUN_ID" RUN_LOG="$LAUNCH_LOG_DIR/${RUN_ID}.log" mkdir -p "$RESULT_DIR" ``` ### Technical Analysis The user-controlled `PROJECT` and `TASK_NAME` arguments are inserted directly into filesystem paths without validation, canonicalization, or containment checks. Although later command execution uses Bash arrays and therefore avoids ordinary shell metacharacter injection, array usage does not prevent path traversal. A project value containing components such as `../` can cause `WORKDIR` and `RESULT_DIR` to resolve outside `REPOS_ROOT` and `RESULTS_BASE`. Path separators in `TASK_NAME` can similarly alter the intended result or log path. The script subsequently creates these directories and launches Claude Code with the derived directory as its working directory. The effective access is limited to the privileges of the account running the Skill, but the configured root boundaries are not enforced. ### Attack Path 1. An attacker or untrusted caller supplies a project argument containing traversal components, such as: ```text /dispatch ../../unintended-target audit-task <prompt> ``` 2. The script constructs: ```text ${REPOS_ROOT}/../../unintended-target ``` 3. `mkdir -p` creates the resolved directory if the process account has permission. 4. The dispatcher launches Claude Code with that unintended location as its working directory. 5. Claude Code can inspect or modify files available to the process ...[truncated 733 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict both identifiers to a conservative allowlist: ```bash if [[ ! "$PROJECT" =~ ^[A-Za-z0-9._-]+$ ]] || [[ "$PROJECT" == "." || "$PROJECT" == ".." ]]; then echo "Invalid project name" >&2 exit 2 fi if [[ ! "$TASK_NAME" =~ ^[A-Za-z0-9._-]+$ ]] || [[ "$TASK_NAME" == "." || "$TASK_NAME" == ".." ]]; then echo "Invalid task name" >&2 exit 2 fi ``` 2. Reject path separators, traversal components, control characters, and newline characters. 3. Canonicalize the configured root and candidate path with `realpath`. 4. Verify that the canonical candidate begins with the canonical root followed by `/`. 5. Perform equivalent containment checks independently for work, result, and log paths. 6. Prefer an internally generated opaque run identifier rather than embedding user-controlled names in filenames. 7. Refuse to create a project directory automatically unless directory creation is an explicitly intended and authorized operation. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/vendor/claude_code_run.py:203
Finding
Automatic Acceptance of Workspace Trust and Permission-Bypass Warnings<![CDATA[ ## Vulnerability Details **File Location**: `scripts/vendor/claude_code_run.py:203-219` **Vulnerability Type**: Automated bypass of interactive security boundaries **Risk Level**: High ### Vulnerable Code ```python # Workspace trust prompt (first run in a new folder). if tmux_wait_for_text(socket_path, target, "Yes, I trust this folder", timeout_s=20): subprocess.run(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"), check=False) time.sleep(0.8) if tmux_wait_for_text(socket_path, target, "Yes, I trust this folder", timeout_s=2): subprocess.run(tmux_cmd(socket_path, "send-keys", "-t", target, "1"), check=False) subprocess.run(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"), check=False) # Bypass Permissions warning prompt (when running with --permission-mode bypassPermissions). # If we send task text before accepting this prompt, it can accidentally choose the default "No, exit". if tmux_wait_for_text(socket_path, target, "Yes, I accept", timeout_s=10): # Select option 2 and confirm. subprocess.run(tmux_cmd(socket_path, "send-keys", "-t", target, "2"), check=False) subprocess.run(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"), check=False) time.sleep(0.8) ``` ### Technical Analysis The runner detects Claude Code's workspace-trust prompt and automatically confirms it. This removes the human review boundary intended to prevent operation in an untrusted directory. When `bypassPermissions` is selected through local configuration, the runner also detects and accepts the corresponding warning. `bypassPermissions` is not enabled by default, so that portion of the issue is conditional. Nevertheless, the implementation deliberately automates acceptance once the mode is configured. This behavior is especially dangerous in combination with the unvalidated work-directory path. A caller can potentially direct the agent to an unintended directory, after which the runner confirms that the ...[truncated 1384 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all code that programmatically accepts workspace-trust prompts. 2. Require explicit operator confirmation before trusting a previously unapproved directory. 3. Enforce canonical work-directory containment before Claude Code is launched. 4. Maintain an administrator-controlled allowlist of trusted repository paths. 5. Reject `bypassPermissions` in unattended and remotely triggered execution modes. 6. If elevated permission modes are operationally necessary, require an explicit per-run authorization separate from user-controlled prompt input. 7. Use a restricted operating-system account, container, or sandbox with access only to the selected repository. 8. Log security decisions without automatically approving them. ]]>

other

Warning
Location
scripts/vendor/claude_code_run.py:340
Finding
Interactive tmux Mode Bypasses the Configured Runtime Timeout<![CDATA[ ## Vulnerability Details **File Location**: `scripts/vendor/claude_code_run.py:222-244, 340-347` **Vulnerability Type**: Timeout enforcement bypass and unmanaged background process **Risk Level**: Medium ### Vulnerable Code The interactive runner reports success and returns without waiting for or terminating the tmux-hosted Claude process: ```python print("Started interactive Claude Code in tmux.") print("To monitor:") print(f" tmux -S {shlex.quote(socket_path)} attach -t {shlex.quote(session)}") print("To snapshot output:") print(f" tmux -S {shlex.quote(socket_path)} capture-pane -p -J -t {shlex.quote(target)} -S -200") if args.interactive_wait_s > 0: time.sleep(args.interactive_wait_s) try: snap = tmux_capture(socket_path, target, lines=200) print("\n--- tmux snapshot (last 200 lines) ---\n") print(snap) except subprocess.CalledProcessError: pass return 0 ``` Automatic mode selection routes slash-prefixed prompts into this path, where `max_seconds` is not used: ```python mode = args.mode if mode == "auto" and looks_like_slash_commands(args.prompt): mode = "interactive" if mode == "interactive": return run_interactive_tmux(args) cmd = build_headless_cmd(args) env = build_agent_teams_env(args) return run_with_pty(cmd, cwd=args.cwd, env=env, max_seconds=args.max_seconds) ``` ### Technical Analysis Timeout enforcement is implemented only in `run_with_pty`, which is used by headless mode. Interactive mode creates a detached tmux session, sends the command and prompt, and then returns success without supervising the tmux process. Because `auto` mode chooses interactive operation whenever a prompt line begins with `/`, a caller can trigger this behavior solely through prompt content. The parent dispatcher may then record successful completion while the Claude Code process continues running independently. This does not install a startup service or cross-reboot backdoor, so it is classified as ...[truncated 1044 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply `max_seconds` to interactive mode as well as headless mode. 2. Retain supervision of the tmux session until completion or timeout. 3. On timeout, terminate the tmux session and verify that all descendant processes have exited. 4. Record a timeout status rather than returning success. 5. Avoid selecting interactive mode solely from user-controlled prompt syntax. 6. Require explicit, trusted configuration to enable interactive mode. 7. Generate a unique tmux session and socket per task to prevent collisions and unintended session replacement. 8. Add cleanup logic for normal exit, timeout, interruption, and startup failure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/vendor/dispatch.sh:111
Finding
Prompts, Session Metadata, and Model Output Stored in Plaintext Without Permission Hardening<![CDATA[ ## Vulnerability Details **File Location**: `scripts/vendor/dispatch.sh:111-165`; `scripts/run_dispatch.sh:116` **Vulnerability Type**: Insecure logging and sensitive-data exposure **Risk Level**: Medium ### Vulnerable Code The complete prompt and callback metadata are written to a JSON file: ```bash jq -n \ --arg name "$TASK_NAME" \ --arg group "$TELEGRAM_GROUP" \ --arg callback_group "$CALLBACK_GROUP" \ --arg callback_dm "$CALLBACK_DM" \ --arg callback_account "$CALLBACK_ACCOUNT" \ --arg session "$CALLBACK_SESSION" \ --arg prompt "$PROMPT" \ --arg workdir "$WORKDIR" \ --arg ts "$(date -Iseconds)" \ --arg agent_teams "${AGENT_TEAMS:-0}" \ '{task_name: $name, telegram_group: $group, callback_group: $callback_group, callback_dm: $callback_dm, callback_account: $callback_account, callback_session: $session, prompt: $prompt, workdir: $workdir, started_at: $ts, agent_teams: ($agent_teams == "1"), status: "running"}' \ > "$META_FILE" ``` The complete command, including the prompt argument, and all runner output are also logged: ```bash echo "🚀 Launching Claude Code..." echo " Command: ${CMD[*]}" echo "" "${CMD[@]}" 2>&1 | tee "$TASK_OUTPUT" ``` The outer launcher redirects this output to another log file: ```bash nohup "${CMD[@]}" >"$RUN_LOG" 2>&1 & ``` ### Technical Analysis The dispatcher persists full prompt text, callback identifiers, session information, command-line contents, and model output. It does not set a restrictive `umask`, explicitly assign secure file modes, redact sensitive values, or define retention and deletion behavior. Actual exposure depends on the permissions of the parent directories and the ambient process umask. If those controls are permissive, other local users or services may read task prompts and outputs. Printing `${CMD[*]}` duplicates the full prompt into the launch log because the prompt is included in the Python runner command. No code implementing network deli ...[truncated 1141 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set a restrictive umask before creating directories or files: ```bash umask 077 ``` 2. Create result and launch-log directories with mode `0700`. 3. Create metadata, output, and log files with mode `0600`. 4. Do not print the assembled command when it contains prompt text. 5. Store only the minimum metadata needed for task tracking. 6. Redact credentials, authorization headers, tokens, and session values before logging. 7. Provide a mode that avoids persisting prompts and raw model output. 8. Implement documented retention limits and secure deletion or rotation. 9. Validate existing directories before use and reject directories owned by an unexpected user or writable by untrusted users. 10. Keep result storage separate from shared or web-accessible directories. ]]>
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (39)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill is presented as a straightforward async dispatcher, but the analyzed behavior includes callback configuration reads, persistent output/metadata storage, message-routing parameters, prompt augmentation, and possibly synchronous execution. Hidden persistence, routing, and prompt injection paths increase data exposure and make it easier for task content or results to be redirected or handled in ways the user did not knowingly approve.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill is presented as a straightforward async dispatcher, but the analyzed behavior includes callback configuration reads, persistent output/metadata storage, message-routing parameters, prompt augmentation, and possibly synchronous execution. Hidden persistence, routing, and prompt injection paths increase data exposure and make it easier for task content or results to be redirected or handled in ways the user did not knowingly approve.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def build_agent_teams_env(args: argparse.Namespace) -> dict[str, str]:
    """Build environment dict with Agent Teams support."""
    env = os.environ.copy()
    if args.agent_teams:
        env["CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"] = "1"
    return env
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes a shell script with user-supplied arguments and references environment-driven behavior, but it declares no tool scope or permission boundaries. That makes the skill's effective capabilities opaque to reviewers and enforcement layers, increasing the chance of unintended shell execution or environment misuse without explicit consent controls.

Session Persistence

Medium
Category
Rogue Agent
Content
exit 0
fi

nohup "${CMD[@]}" >"$RUN_LOG" 2>&1 &
PID=$!

# Quick startup sanity check: allow immediate successful completion,
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.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The wrapper explicitly supports interactive tmux sessions and slash-command handling, which conflicts with the skill's stated purpose of non-blocking headless dispatch. This scope expansion is dangerous because it introduces persistent operator-like interaction paths and richer command surfaces than consumers of the manifest would reasonably expect.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Agent Teams support allows multi-agent orchestration beyond the dispatch skill's described purpose. In a security review, this matters because it can amplify resource usage, coordination complexity, and the number of autonomous actions performed under one invocation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
script_bin = which("script")
    proc_args = [script_bin, "-q", "-c", cmd_str, "/dev/null"] if script_bin else cmd

    proc = subprocess.Popen(
        proc_args,
        cwd=cwd,
        text=True,
Confidence
89% confidence
Finding
This wrapper executes a user-controlled Claude CLI command and, when `script` is present, passes a single shell command string via `script -c`. Although arguments are shell-quoted, the code still launches an external program based on user/environment-controlled inputs (`claude_bin`, prompt/options, extra args), so this is a real command-execution sink with meaningful security impact in an agent skill context.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def tmux_capture(socket_path: str, target: str, lines: int = 200) -> str:
    out = subprocess.check_output(
        tmux_cmd(socket_path, "capture-pane", "-p", "-J", "-t", target, "-S", f"-{lines}"),
        text=True,
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_output (code execution)

Medium
Category
Data Flow
Content
def tmux_capture(socket_path: str, target: str, lines: int = 200) -> str:
    out = subprocess.check_output(
        tmux_cmd(socket_path, "capture-pane", "-p", "-J", "-t", target, "-S", f"-{lines}"),
        text=True,
    )
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Persistent tmux session management is an unjustified capability for a dispatch helper meant to launch headless async jobs. It enables long-lived hidden execution contexts, post-launch interaction, prompt automation, and cross-session interference, all of which materially increase attack surface and reduce transparency.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
session = args.tmux_session
    target = f"{session}:0.0"

    subprocess.run(tmux_cmd(socket_path, "kill-session", "-t", session), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    subprocess.check_call(tmux_cmd(socket_path, "new", "-d", "-s", session, "-n", "shell"))

    cwd = args.cwd or os.getcwd()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
session = args.tmux_session
    target = f"{session}:0.0"

    subprocess.run(tmux_cmd(socket_path, "kill-session", "-t", session), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    subprocess.check_call(tmux_cmd(socket_path, "new", "-d", "-s", session, "-n", "shell"))

    cwd = args.cwd or os.getcwd()
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
target = f"{session}:0.0"

    subprocess.run(tmux_cmd(socket_path, "kill-session", "-t", session), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    subprocess.check_call(tmux_cmd(socket_path, "new", "-d", "-s", session, "-n", "shell"))

    cwd = args.cwd or os.getcwd()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
target = f"{session}:0.0"

    subprocess.run(tmux_cmd(socket_path, "kill-session", "-t", session), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    subprocess.check_call(tmux_cmd(socket_path, "new", "-d", "-s", session, "-n", "shell"))

    cwd = args.cwd or os.getcwd()
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
# Set Agent Teams env var inside tmux session if enabled
    if args.agent_teams:
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", "export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"))
        subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))
        time.sleep(0.3)

    claude_parts = [args.claude_bin]
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
claude_parts += args.extra

    launch = f"cd {shlex.quote(cwd)} && " + " ".join(shlex.quote(p) for p in claude_parts)
    subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", launch))
    subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))

    # Workspace trust prompt (first run in a new folder).
Confidence
95% confidence
Finding
The code assembles a shell command string (`cd ... && ...`) and sends it into a tmux shell for execution. Even though components are quoted, this intentionally converts user-influenced values (`cwd`, `claude_bin`, flags, extra args) into shell-interpreted text, making the tmux shell an execution sink and significantly increasing the blast radius if inputs or upstream trust assumptions fail.

Tainted flow: 'socket_path' from os.environ.get (line 187, credential/environment) → subprocess.check_call (code execution)

Medium
Category
Data Flow
Content
claude_parts += args.extra

    launch = f"cd {shlex.quote(cwd)} && " + " ".join(shlex.quote(p) for p in claude_parts)
    subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "-l", "--", launch))
    subprocess.check_call(tmux_cmd(socket_path, "send-keys", "-t", target, "Enter"))

    # Workspace trust prompt (first run in a new folder).
Confidence
84% confidence
Finding
The tainted socket path can redirect where the shell-launch command is sent, so an attacker controlling the environment may cause this wrapper to type and execute commands in an unintended tmux server/session. Because line 223 sends an executable shell command, misrouting it has real integrity and confidentiality implications.

Static analysis

No suspicious patterns detected.