Night Shift

Security checks across malware telemetry 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.

SkillSpector

By NVIDIA
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
result = subprocess.run( args, cwd=worktree_path, capture_output=True, text=True, timeout=timeout, )

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
result = subprocess.run( [ str(CURSOR_CLI), "-p", str(prompt_file), "--model", model, "--trust", "--

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
result = subprocess.run( [ "python3", "-c", f"import sys; sys.path.insert(0, '{worktree}'); import {module}; print('OK')",

subprocess module call

Medium
Category
Dangerous Code Execution
Content
)

        try:
            result = subprocess.run(
                args,
                cwd=worktree,
                capture_output=True,
Confidence
94% confidence
Finding
result = subprocess.run( args, cwd=worktree, capture_output=True, text=True, timeout=timeout, )

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
subprocess.run( ["git", "branch", "-D", branch], cwd=WORKSPACE, capture_output=True, text=True )

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
result = subprocess.run( ["git", "worktree", "add", "-b", branch, str(worktree_path), base_branch], cwd=WORKSPACE, capture_output=True, text=True, )

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
subprocess.run( ["chown", "-R", "coder:coder", str(worktree_path)], capture_output=True, text=True, )

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
subprocess.run( ["chmod", "-R", "755", str(worktree_path)], capture_output=True, text=True )

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
subprocess.run( ["git", "config", "--global", "--add", "safe.directory", str(worktree_path)], capture_output=True, text=True, )

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
subprocess.run( ["git", "add", "-A"], cwd=worktree_path, capture_output=True, text=True )

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
result = subprocess.run( ["git", "commit", "-m", message, "--allow-empty", "--no-verify"], cwd=worktree_path, capture_output=True, text=True, )

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
subprocess.run( ["git", "reset", "--hard", "HEAD~1"], cwd=worktree_path, capture_output=True, text=True, )

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
subprocess.run( ["git", "clean", "-fd"], cwd=worktree_path, capture_output=True, text=True )

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
subprocess.run( ["git", "worktree", "remove", str(worktree_path), "--force"], cwd=WORKSPACE, capture_output=True, text=True, )

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
result = subprocess.run( ["git", "worktree", "remove", str(worktree_path), "--force"], cwd=WORKSPACE, capture_output=True, text=True, )

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
result = subprocess.run( ["bash", router_bin, phase_prompt], capture_output=True, text=True, timeout=timeout + 30, env={**os.environ

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
result = subprocess.run( [ str(CURSOR_CLI), "-p", str(prompt_file), "--model", model, "--trust", "--

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.

VirusTotal

64/64 vendors flagged this skill as clean.

View on VirusTotal