Back to skill

Security audit

Night Shift

Security checks for vulnerabilities and agentic risk

Overview

Night Shift is a disclosed autonomous coding runner, but it grants broad unattended execution and repository mutation authority with weak containment and an external-repo copying workflow that users should review carefully.

Install only in a disposable or low-risk git workspace first. Review every queued plan and generated phase before approval, avoid `plan steal` unless you own or are licensed to reuse the source, keep production credentials out of the runner environment, prefer dry-run, and inspect reports/diffs before merging. Do not run it unattended against sensitive repositories until workspace paths, runner binaries, stored logs, and cleanup behavior are locked down.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (26)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
duration_seconds=0,
                execution_method="shell",
            )
        result = subprocess.run(
            args,
            cwd=worktree_path,
            capture_output=True,
Confidence
95% confidence
Finding
This path executes a command derived from phase input as an arbitrary process in the worktree. Although shlex.split avoids classic shell metacharacter injection, it still permits attacker-controlled selection of any executable and arguments, which is effectively arbitrary command execution if untrusted plans or prompts can reach execution_method='shell'.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        # Run Cursor CLI
        result = subprocess.run(
            [
                str(CURSOR_CLI),
                "-p", str(prompt_file),
Confidence
98% confidence
Finding
This code launches an external agent binary with a prompt derived from input, a caller-controlled working directory, inherited environment variables, and the explicit `--trust` flag that grants broad tool access. In the context of an agent skill designed for autonomous code execution, this is a real code-execution boundary: if an attacker can influence `phase_prompt`, `worktree_path`, or the selected binary path, they can cause arbitrary commands, file modification, and data access inside the runner's execution context.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not module:
            return True, "No module specified (skipping)"

        result = subprocess.run(
            [
                "python3",
                "-c",
Confidence
98% confidence
Finding
The import check runs `python3 -c` with attacker-controlled `worktree` added to `sys.path` and then imports a configurable module. Importing a Python module executes its top-level code, so a malicious repository can achieve arbitrary code execution during verification even if the stated goal is only to test importability.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
)

        try:
            result = subprocess.run(
                args,
                cwd=worktree,
                capture_output=True,
Confidence
94% confidence
Finding
This function executes configurable commands from verification settings inside the target worktree. Although it avoids `shell=True` and uses an executable allowlist, commands like `python`, `node`, `npm`, `cargo`, `go`, and `make` can still execute attacker-controlled code from the repository during tests/builds, making arbitrary code execution possible in the verifier context.

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

Medium
Category
Data Flow
Content
WORKTREES_DIR.mkdir(parents=True, exist_ok=True)

    # Now safe to delete the branch
    subprocess.run(
        ["git", "branch", "-D", branch], cwd=WORKSPACE, capture_output=True, text=True
    )
Confidence
91% confidence
Finding
`WORKSPACE` is derived from `OPENCLAW_WORKSPACE` without validation, so an attacker controlling the environment can redirect destructive git operations into an arbitrary repository. In this call, that can force-delete a branch in the wrong repo, causing unintended data loss or repository tampering within the process's privileges.

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

Medium
Category
Data Flow
Content
)

    # Create worktree with new branch
    result = subprocess.run(
        ["git", "worktree", "add", "-b", branch, str(worktree_path), base_branch],
        cwd=WORKSPACE,
        capture_output=True,
Confidence
92% confidence
Finding
Because `WORKSPACE` is environment-controlled and `base_branch` is accepted without validation, this function can operate on an unintended repository or unexpected reference. In a background automation context, that means an attacker or misconfiguration could create branches/worktrees in the wrong repo, stage later changes there, and confuse review or redirect automated modifications.

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

Medium
Category
Data Flow
Content
subprocess.run(
                ["chmod", "o+x", str(dir_path)], capture_output=True, text=True
            )
    subprocess.run(
        ["chown", "-R", "coder:coder", str(worktree_path)],
        capture_output=True,
        text=True,
Confidence
96% confidence
Finding
`worktree_path` is ultimately derived from an environment-influenced workspace path and unvalidated `plan_id`, then passed to recursive `chown`. If an attacker can influence the resolved path via symlinks or crafted identifiers, the code may recursively retake ownership of unintended directories, which is especially dangerous if the process runs with elevated privileges.

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

Medium
Category
Data Flow
Content
capture_output=True,
        text=True,
    )
    subprocess.run(
        ["chmod", "-R", "755", str(worktree_path)], capture_output=True, text=True
    )
Confidence
96% confidence
Finding
This recursively sets mode `755` on an environment-influenced path without checking that the path remains inside the managed worktrees directory. If path resolution is abused, the code could make unrelated directories world-readable/executable, widening access to sensitive repository contents or system paths.

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

Medium
Category
Data Flow
Content
# Allow root to run git commands on coder-owned worktree
    # (git refuses "dubious ownership" otherwise)
    subprocess.run(
        ["git", "config", "--global", "--add", "safe.directory", str(worktree_path)],
        capture_output=True,
        text=True,
Confidence
95% confidence
Finding
Adding an unvalidated worktree path to global git `safe.directory` permanently expands trust for that location. If an attacker can influence the path, this can disable Git's ownership safety checks for unintended directories, increasing the chance that later root-run git commands operate on attacker-controlled repositories.

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

Medium
Category
Data Flow
Content
message = f"Phase {phase_id}: {title}"

    # Stage all changes
    subprocess.run(
        ["git", "add", "-A"], cwd=worktree_path, capture_output=True, text=True
    )
Confidence
90% confidence
Finding
`worktree_path` is derived from unvalidated inputs and then used as the working directory for `git add -A`, which stages everything in that repo. If the path points to an attacker-chosen or wrong repository, the automation can stage unintended files and feed them into later commits, causing integrity loss in a background execution workflow.

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

Medium
Category
Data Flow
Content
# Commit (skip pre-commit hooks — worktree has full repo copy which
    # triggers skill/cron validation hooks on unrelated files)
    result = subprocess.run(
        ["git", "commit", "-m", message, "--allow-empty", "--no-verify"],
        cwd=worktree_path,
        capture_output=True,
Confidence
91% confidence
Finding
Committing in an unvalidated worktree path can record attacker-influenced or unintended repository contents, and the use of `--no-verify` further weakens safeguards. In an automated background agent, this can silently produce commits in the wrong repository or bypass local policy checks intended to prevent unsafe changes.

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

Medium
Category
Data Flow
Content
return False

    # Reset to previous commit
    subprocess.run(
        ["git", "reset", "--hard", "HEAD~1"],
        cwd=worktree_path,
        capture_output=True,
Confidence
94% confidence
Finding
This performs `git reset --hard HEAD~1` in a path derived from unvalidated inputs, which can destroy committed work in an unintended repository if the path is redirected. In an automated system, that creates a significant integrity risk because data loss can occur silently and repeatedly.

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

Medium
Category
Data Flow
Content
)

    # Clean untracked files
    subprocess.run(
        ["git", "clean", "-fd"], cwd=worktree_path, capture_output=True, text=True
    )
Confidence
94% confidence
Finding
`git clean -fd` irreversibly deletes untracked files in whatever repository `worktree_path` points to. If that path is attacker-influenced or misresolved, the code can delete arbitrary project files in the wrong repo during unattended execution.

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

Medium
Category
Data Flow
Content
# Clean up existing worktree if present (must remove BEFORE deleting branch)
    if worktree_path.exists():
        subprocess.run(
            ["git", "worktree", "remove", str(worktree_path), "--force"],
            cwd=WORKSPACE,
            capture_output=True,
Confidence
92% confidence
Finding
The code removes a worktree in a repo selected by the environment-derived `WORKSPACE`, so a hostile or malformed environment can redirect forced deletion into an unintended repository. This is particularly risky in background automation because the removal is forced and followed by filesystem cleanup.

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

Medium
Category
Data Flow
Content
worktree_path = WORKTREES_DIR / plan_id

    if worktree_path.exists():
        result = subprocess.run(
            ["git", "worktree", "remove", str(worktree_path), "--force"],
            cwd=WORKSPACE,
            capture_output=True,
Confidence
92% confidence
Finding
This forced worktree removal uses an unvalidated workspace path and can therefore operate on the wrong repository. In unattended execution, that can silently remove a legitimate worktree belonging to another project or tenant within the process's access scope.

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

Medium
Category
Data Flow
Content
try:
        # Call unified-router, which routes to GLM-5.1/Cursor/Opus
        result = subprocess.run(
            ["bash", router_bin, phase_prompt],
            capture_output=True,
            text=True,
Confidence
89% confidence
Finding
The executed script path is derived from _WORKSPACE, which can come from the OPENCLAW_WORKSPACE environment variable. An attacker who can influence that environment can redirect execution to an arbitrary run.sh under a controlled workspace, resulting in arbitrary code execution when phases are run.

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

Medium
Category
Data Flow
Content
try:
        # Run Cursor CLI
        result = subprocess.run(
            [
                str(CURSOR_CLI),
                "-p", str(prompt_file),
Confidence
99% confidence
Finding
`CURSOR_CLI` is sourced from the environment and then executed directly as a program. In a system intended for background autonomous execution, allowing an environment variable to select the executable creates an easy arbitrary code execution primitive: any actor able to influence the process environment can replace the trusted agent binary with a malicious one, which then runs with inherited environment variables and access to the worktree.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises and normalizes powerful capabilities including filesystem read/write, git worktrees, subprocess execution, optional model-provider calls, and environment-variable access, but the static finding indicates these are not declared through the expected permission model. That creates a transparency and review gap: operators may approve or install the skill without clearly understanding it can execute shell commands, access environment-provided secrets, and modify repositories unattended.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The function modifies ownership and permissions broadly (`chown -R`, `chmod -R 755`, and `o+x` on parent directories) and also weakens Git's safety model via global `safe.directory`. In this skill's context—isolated worktrees for background agent execution—these changes expand access and trust beyond what is necessary, increasing the blast radius if the path or repo is attacker-controlled or misconfigured.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The file defines an explicit workflow named around stealing a repository, including cloning an external repo, extracting reusable patterns, and integrating them as a local skill. That goes beyond neutral phase generation and materially enables code appropriation behavior, which is especially risky in an agentic execution system that may later run these generated plans automatically.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The task classifier automatically maps any repo URL or copy-oriented wording into a 'steal' task type, normalizing unauthorized copying as a standard operation. This creates a dangerous default that can silently route benign-looking inputs into an appropriation pipeline without any permission, licensing, or ownership checks.

Vague Triggers

Medium
Confidence
97% confidence
Finding
Using "good night" as a trigger is risky because it is a common conversational phrase that can be said casually, yet in this skill it starts queued execution of approved plans with shell/subagent/code-execution behavior. In this context, accidental invocation is more dangerous than in a harmless chat skill because the action can launch unattended repository changes and subprocess execution.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The checkpoint data persists git diff summaries and execution metadata to disk under a shared workspace path without any access-control, retention, or redaction logic. In an agentic coding workflow, diffs and summaries can easily contain proprietary code, secrets, or sensitive task details, so writing them to disk creates an information-disclosure risk if the workspace is readable by other users, tools, or later runs.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code writes raw phase stdout and stderr directly to disk, which can capture API keys, tokens, stack traces, prompts, source code, or other sensitive material emitted during execution. Because this skill explicitly manages background execution and reports, persistent logs in the workspace meaningfully increase exposure and can leak data across sessions or to anyone with filesystem access.

Ssd 4

High
Confidence
98% confidence
Finding
The staged flow is explicitly built to clone a repository, extract reusable implementation patterns, and reincorporate them into a local skill. In the context of an automation skill that queues and later executes work, this is a strong indicator of deliberate enablement of IP theft or unauthorized code reuse rather than an accidental design flaw.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/queue.py:14

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/verifier.py:23