Back to skill

Security audit

spex

Security checks across malware telemetry and agentic risk

Overview

This SDLC automation skill is mostly purpose-aligned, but it needs Review because installation and helper commands can alter the local environment and run commands with broader authority than the top-level skill disclosure makes clear.

Install only if you are comfortable with a development automation tool that can modify repositories, create commits and merges, run local hook executables, install Python dependencies, and place a `spex` command in `~/.local/bin`. Prefer running `spex init --dry-run` first, use `--skip-deps` if you want to manage dependencies yourself, inspect `.spex/hooks/` before workflows, avoid untrusted `PAGER` values, and do not enable debug logging around secrets or proprietary output.

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

subprocess module call

Medium
Category
Dangerous Code Execution
Content
Raises subprocess.CalledProcessError on failure.
    """
    branch_name = _strip_refs_prefix(branch_name)
    subprocess.run(
        ["git", "switch", "-c", branch_name],
        capture_output=True,
        text=True,
Confidence
91% confidence
Finding
subprocess.run( ["git", "switch", "-c", branch_name], capture_output=True, text=True, check=True, cwd=cwd, )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def switch_branch(branch_name: str, cwd: str | Path | None = None) -> None:
    """Switch to the given branch. Raises subprocess.CalledProcessError on failure."""
    branch_name = _strip_refs_prefix(branch_name)
    subprocess.run(
        ["git", "switch", branch_name],
        capture_output=True,
        text=True,
Confidence
92% confidence
Finding
subprocess.run( ["git", "switch", branch_name], capture_output=True, text=True, check=True, cwd=cwd, )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
) -> None:
    """Set the git branch description. Branch must be short format (no refs/heads/)."""
    branch = _strip_refs_prefix(branch)
    subprocess.run(
        ["git", "config", f"branch.{branch}.description", description],
        capture_output=True,
        text=True,
Confidence
88% confidence
Finding
subprocess.run( ["git", "config", f"branch.{branch}.description", description], capture_output=True, text=True, check=True, cwd=cwd, )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
target: str, source: str, cwd: str | Path | None = None,
) -> None:
    """Merge source branch into target. Raises CalledProcessError on conflict."""
    subprocess.run(
        ["git", "switch", target],
        capture_output=True,
        text=True,
Confidence
92% confidence
Finding
subprocess.run( ["git", "switch", target], capture_output=True, text=True, check=True, cwd=cwd, )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
check=True,
        cwd=cwd,
    )
    subprocess.run(
        ["git",
         "-c", "merge.branchdesc=true",
         "-c", "merge.log=true",
Confidence
94% confidence
Finding
subprocess.run( ["git", "-c", "merge.branchdesc=true", "-c", "merge.log=true", "merge", source, "--no-ff", "--no-edit"], capture_output

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return None

    payload = json.dumps(event_data)
    result = subprocess.run(
        [str(hook_path)],
        input=payload,
        capture_output=True,
Confidence
91% confidence
Finding
result = subprocess.run( [str(hook_path)], input=payload, capture_output=True, text=True, cwd=workdir, )

subprocess module call

Medium
Category
Dangerous Code Execution
Content
path: Path string of the working directory.
        command: Shell command string to execute.
    """
    result = subprocess.run(command, shell=True, cwd=path)
    sys.exit(result.returncode)
Confidence
99% confidence
Finding
result = subprocess.run(command, shell=True, cwd=path)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return
    pager = os.environ.get("PAGER", "less -R")
    try:
        proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE)
        proc.communicate(input=text.encode())
    except (BrokenPipeError, OSError):
        print(text)
Confidence
96% confidence
Finding
proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE)

Tainted flow: 'pager' from os.environ.get (line 25, credential/environment) → subprocess.Popen (code execution)

Medium
Category
Data Flow
Content
return
    pager = os.environ.get("PAGER", "less -R")
    try:
        proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE)
        proc.communicate(input=text.encode())
    except (BrokenPipeError, OSError):
        print(text)
Confidence
98% confidence
Finding
proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE)

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill advertises no declared permissions, yet its documented behavior routes into command SOPs that may perform environment access, file reads/writes, and shell-driven implementation steps. This creates a capability-transparency gap: users and reviewers cannot accurately assess what the skill may do before invocation, increasing the risk of unexpected code execution or repository modification.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The skill includes a generic mechanism to discover and run arbitrary local executables as hooks, which materially expands capability beyond simple SDLC orchestration. In an agent skill context, that creates a powerful execution primitive that could be abused for persistence, lateral actions, or running unintended code from a repository-controlled location.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The hook event envelope includes user name, email, working directory, timestamp, and payload, and passes that data to external executables. This is an unnecessary exposure of potentially sensitive metadata unless clearly required, and it increases privacy and targeting risk if hooks are untrusted or repository-supplied.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
An initialization command for an SDLC skill unexpectedly performs package installation from external sources, expanding its privilege and trust boundary beyond local setup. This is dangerous because users may run init expecting harmless configuration, but it can alter the Python environment and introduce supply-chain risk without clear separation of duties.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The code directly queries PyPI, selects a wheel, downloads it, and extracts its contents into site-packages without using standard package-management safety mechanisms such as dependency resolution, RECORD validation, hash pinning, or trust verification. This creates a strong supply-chain compromise path: a malicious or tampered package can place arbitrary Python modules into the runtime environment and achieve code execution when later imported.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The utility is documented as a helper to get or set values in a spec's meta.json, but the --pre-action option causes it to invoke hooks.run_pre_action before writing. This expands the tool from passive metadata manipulation into execution of potentially arbitrary project-defined hook logic, which can trigger unintended commands or side effects whenever an attacker can influence invocation arguments or hook configuration. In the Spex skill context, this is more dangerous because the tool participates in an SDLC automation workflow where hooks are likely trusted and may run with repository or developer privileges.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The command is described and named as an 'open' helper, but it also supports arbitrary shell execution through `--run`. This mismatch increases the chance that higher-level agents or users invoke it under the assumption that it is low risk, when it can actually execute commands in a selected directory.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Embedding shell-command execution in a file-browser utility creates unnecessary attack surface and violates least privilege. In a skill ecosystem, unjustified execution features are more dangerous because they can be abused by prompt/parameter manipulation to turn harmless workflows into host command execution.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The modify-todo command is described as a prompt-rendering operation, but it performs a state-changing write to todo.json by filtering out all undone tasks before rendering. This can silently destroy task state and workflow history, and because it happens automatically during a rendering path, users or higher-level agents may trigger irreversible data loss without realizing the command is destructive.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
This code path introduces undeclared stateful behavior in a command that appears to only construct prompt text. Hidden writes violate least surprise and can be abused by orchestration layers, wrappers, or users that assume the operation is side-effect free, causing corruption of spec task data and inconsistent SDLC state.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The `apply` command is bound to broad aliases like `run`, `do`, and `go`, which are common conversational words and can be triggered unintentionally during free-form use. In this skill's context, `apply` is the code-generation/execution path, so accidental routing could initiate implementation workflows, file changes, or shell-backed actions when the user did not intend to do so.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill triggers a merge and possible archive operation directly once a spec is resolved, with no explicit user confirmation step before performing a state-changing action. In an interactive agent setting, auto-selection of a spec and unconditional execution can cause unintended branch merges or archival of work, especially if the user invoked the command ambiguously or the agent misresolved the target.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The router permits free-form intent inference with a 90% confidence threshold and allows routing with `$prompt`, which can cause unintended command execution when natural-language input is ambiguously mapped. In a skill that manages SDLC workflows and can trigger downstream command SOPs with file writes, merges, or implementation actions, broad inference increases the risk of misrouting unsafe or user-unintended operations.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
When debug mode is enabled, this code persists full command arguments plus captured stdout/stderr to `debug.log`. In an SDLC automation skill, those streams can easily contain secrets, access tokens, prompts, proprietary code, filesystem paths, or other sensitive material, creating a confidentiality risk if logs are later read, archived, merged, or committed.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
User identity and workdir details are packaged and delivered to hook scripts without any evident user-facing disclosure or consent at the call site. If hooks are attacker-controlled or unexpectedly present, this leaks contextual information that can aid phishing, exfiltration, or targeted follow-on actions.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The code launches executable hook scripts silently as subprocesses, with no visible indication that external code is being run. In this skill context, undisclosed execution is especially risky because repository or local environment contents may influence which executable is selected and run.

VirusTotal

VirusTotal findings are pending for this skill version.

View on VirusTotal

Static analysis

No suspicious patterns detected.