Back to skill

Security audit

元守 yotta-publish-guard

Security checks for vulnerabilities and agentic risk

Overview

This skill fits its publishing-helper purpose, but its package inspection and executable publish paths can run local project code and publicly upload broad directory contents, so it needs careful review before installation.

Install only if you trust the publisher and understand that this is an active release automation tool, not passive documentation. Avoid running pack or publish on untrusted skill directories; pin the npm version when installing; review the exact files to be published; run a secret scan before --exec; and prefer explicit --agent or --dir installs over global or auto-detected installation.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/yotta_publish_guard.py:458
Finding
Untrusted package lifecycle scripts execute during pack inspection## Vulnerability Details **File Location**: `scripts/yotta_publish_guard.py:458-471` **Vulnerability Type**: Execution of untrusted npm lifecycle scripts **Risk Level**: High ### Vulnerable Code ```python def _npm_pack_files(d: Path): """Return (files, used_npm).""" npm = shutil.which("npm") if npm: cache = tempfile.mkdtemp(prefix="pg-npmcache-") code, out, err = run_cmd( [npm, "pack", "--dry-run", "--json", "--cache", cache], cwd=str(d)) ``` ### Technical Analysis The `pack` command is presented as an inspection operation for a target skill directory. However, `npm pack`, including dry-run packaging, may execute lifecycle scripts defined by the target's `package.json`, such as `prepack`, `prepare`, and `postpack`. The command does not include `--ignore-scripts`. Consequently, inspecting an untrusted or compromised skill can execute attacker-controlled commands with the privileges and environment of the user running the guard. The use of an argument array prevents shell metacharacter injection into this particular subprocess call, but it does not prevent npm itself from intentionally running package lifecycle scripts. This behavior exceeds the minimum privileges required to enumerate package contents. A package audit should not execute code from the package being audited. ### Attack Path 1. An attacker supplies a skill directory containing a `package.json` such as: ```json { "name": "apparently-safe-skill", "version": "1.0.0", "scripts": { "prepack": "node malicious-script.js" } } ``` 2. The victim runs: ```bash python3 scripts/yotta_publish_guard.py pack ./apparently-safe-skill ``` 3. The guard invokes `npm pack --dry-run` in the attacker-controlled directory. 4. npm executes the lifecycle script before returning the package manifest. 5. The malicious process runs with the victim's account priv ...[truncated 557 chars]
Remediation
## Remediation Suggestions - Add `--ignore-scripts` to every npm operation used for inspection: ```python [npm, "pack", "--dry-run", "--json", "--ignore-scripts", "--cache", cache] ``` - Prefer static package-file calculation or a sandboxed subprocess when inspecting untrusted projects. - Run packaging inspection with a minimal environment that excludes authentication tokens and unrelated secrets. - Document that inspected directories must be treated as untrusted input. - Add a regression test containing a `prepack` script that creates a marker file, then verify that invoking `pack` never creates that file. - Remove temporary npm cache directories in a `finally` block after inspection.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/yotta_publish_guard.py:710
Finding
Publish workflow can commit and publicly upload unintended sensitive files## Vulnerability Details **File Location**: `scripts/yotta_publish_guard.py:710-731` **Vulnerability Type**: Overbroad file staging and publication without secret or package-content enforcement **Risk Level**: High ### Vulnerable Code ```python if "github" in channels: plan.append(("git init", ["git", "init"])) plan.append(("git add .", ["git", "add", "."])) plan.append(("git commit", ["git", "commit", "-m", "feat: initial release v%s" % pkg_v])) plan.append(("gh repo create", ["gh", "repo", "create", cfg.github_org + "/" + slug, "--public", "--source=.", "--push", "--description", desc])) if "npm" in channels: npm_cmd = ["npm", "publish", "--registry=https://registry.npmjs.org/"] plan.append(("npm publish", npm_cmd)) if "clawhub" in channels: plan.append(("clawhub publish", ["clawhub", "publish", str(d), "--name", "%s %s" % (zh, slug), "--owner", owner, "--version", pkg_v, "--categories", cats, "--topics", topics])) ``` ### Technical Analysis The executable publish mode stages the entire target directory with `git add .`, commits it, creates a public GitHub repository, and pushes the commit. The publication gate calls `validate_dir`, but that validator does not perform secret detection or enforce an explicit allowlist of files. The same workflow invokes `npm publish` and `clawhub publish` without first requiring a successful package-content inspection. Although npm may honor `.npmignore`, `.gitignore`, and the `files` field, the guard does not ensure that these controls exist or exclude sensitive files. This creates a least-privilege violation at the data level: the workflow needs to publish a defined release artifact, but instead grants the publication commands access to the entire target tree. Th ...[truncated 1673 chars]
Remediation
## Remediation Suggestions - Replace `git add .` with an explicit release-file allowlist derived from a reviewed manifest. - Before any publication, require: - secret scanning; - package-content inspection; - version alignment; - a review of the exact files and destinations; - explicit confirmation immediately before execution. - Use `git status --short` and `git diff --cached --name-only` to display the precise staged set. - Refuse to publish common sensitive files such as `.env`, private keys, credential files, authentication databases, and unredacted logs. - Run `npm pack --dry-run --ignore-scripts --json`, validate the returned manifest, and publish the reviewed tarball rather than an unchecked working tree. - Create repositories as private by default, requiring a separate explicit option for public visibility. - Add tests demonstrating that unignored sensitive fixtures block publication.

T03 · Remote Payload Retrieval and Execution

Warning
Location
README.md:102
Finding
Recommended unpinned npx installation retrieves and executes a mutable remote package## Vulnerability Details **File Location**: `README.md:102-109` **Vulnerability Type**: Unpinned remote package retrieval and execution **Risk Level**: Medium ### Vulnerable Code ```text ### Method 1: npm one-liner (recommended) # Optional China mirror: npm config set registry https://registry.npmmirror.com npx -y @yottameta/yotta-publish-guard --agent <agent-name> npx -y @yottameta/yotta-publish-guard --dir <your-skills-dir> ``` The equivalent unpinned instructions also appear in `README.zh-CN.md:120-122`. ### Technical Analysis The recommended command uses `npx -y` without a version or integrity pin. It therefore retrieves the package version currently selected by the configured npm registry and immediately executes its declared binary without interactive confirmation. The effective code executed by this command can change after the audited repository version is reviewed. Compromise of the publisher account, registry metadata, mirror, or a future release can turn the documented installation command into a remote payload execution channel. The optional recommendation to change the global npm registry to a mirror further changes the trust boundary for later npm operations. The static pre-scan references `README.md:16-18` and `README.zh-CN.md:21-23`. Those specific lines are passive GitHub and Shields.io links or badge images; they do not download an executable and are not themselves vulnerabilities. The executable retrieval occurs in the later `npx` installation instructions. ### Attack Path 1. An attacker compromises the package publisher account, registry namespace, mirror, or release process. 2. The attacker publishes a malicious newer version under `@yottameta/yotta-publish-guard`. 3. A user follows the recommended unversioned `npx -y` command. 4. npx resolves the mutable latest version, downloads it, and executes `bin/install.js`. 5. The malicious package runs with the user's privileges and can ...[truncated 530 chars]
Remediation
## Remediation Suggestions - Pin installation commands to an audited exact version: ```text npx -y @yottameta/yotta-publish-guard@0.3.0 --agent <agent-name> ``` - Publish and document package integrity hashes or signed provenance, and instruct users to verify them. - Avoid recommending persistent global registry changes. Prefer a command-scoped registry option: ```text npx --registry=https://registry.npmjs.org/ -y @yottameta/yotta-publish-guard@0.3.0 --agent <agent-name> ``` - Protect publisher accounts with phishing-resistant MFA and restricted automation tokens. - Use npm provenance and a controlled CI release workflow. - Keep manual installation from a pinned commit or verified archive as an alternative for high-assurance environments.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises shell execution, file read/write, and environment-variable use in its behavior, but the manifest declares no permissions or equivalent disclosure. This creates a transparency and trust problem: users or orchestration layers may assume the skill is passive documentation when it can actually invoke local CLIs, inspect local files, and modify state during install/publish flows.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The documented purpose is a pre-release guard, but the finding indicates additional installer behavior that copies/deploys the skill into agent directories, including global and auto-detected locations. Hidden installation behavior broadens the attack surface and can lead to persistence or unintended modification of multiple local environments beyond what a user expects from a validation tool.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The trigger list includes broad phrases such as '查重' and '版本对齐' alongside generic pre-publish wording, which can cause the skill to activate in conversations that merely mention duplicate checking or version alignment without intending to invoke this tool. In an agent environment, over-broad triggers can lead to unintended workflow execution, context capture, or suggestion of release-related actions at the wrong time.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The documented trigger phrases are broad and include generic terms like '查重' and '版本对齐', which can match ordinary user requests outside the narrow publish-guard context. In an agent skill system, overly permissive activation increases the chance of unintended invocation, causing the skill to run in the wrong workflow and potentially influence actions around publishing or repository operations without explicit user intent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation describes commands that can execute publishes, initialize repositories, create commits, and invoke external platform CLIs, but it does not present a strong, front-and-center warning that these actions change local and remote state. Users may rely on examples and accidentally run mutating commands in the wrong repository or account context, causing unintended publication or repository changes.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The description embeds very broad trigger phrases such as '查重', '版本对齐', and 'publish' alongside narrower phrases. In an agent-skill environment, overly generic triggers can cause the skill to activate outside the intended pre-publish context, leading to unsolicited execution of release-check or publish-wrapper behavior and increasing the chance of disruptive or unsafe actions.

Unvalidated Output Injection

High
Category
Output Handling
Content
label = cmd[0]
    cmd = _win_cmd(cmd)
    try:
        r = subprocess.run(cmd, cwd=cwd, env=env, capture_output=True,
                           timeout=timeout)
        out = r.stdout.decode("utf-8", errors="replace")
        err = r.stderr.decode("utf-8", errors="replace")
Confidence
83% confidence
Finding
The tool executes external binaries by name (for example npm, gh, clawhub, git, cmd.exe) using the current PATH and largely inherited process environment. In a publish-helper context, an attacker who can influence PATH, COMSPEC, or place trojan binaries earlier in search order could cause this trusted tool to run unintended programs, leading to arbitrary code execution under the user's account during check, name lookup, or publish flows.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.insecure_tls_verification

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
test/install.test.js:12

HTTPS certificate verification is disabled.

Warn
Code
suspicious.insecure_tls_verification
Location
scripts/test_yotta_publish_guard.py:428