Back to skill

Security audit

元序 yotta-workflow

Security checks for vulnerabilities and agentic risk

Overview

The workflow skill is mostly coherent, but users should review it because it automatically persists project state and its recommended installers have supply-chain and filesystem-safety risks.

Review this before installing. The workflow itself is not exfiltrating data, but it is designed to create and keep project state under .workflow, so avoid using it in repositories where logs or decisions may contain secrets unless you manage that directory carefully. Prefer a pinned package version or a reviewed local checkout instead of the unpinned npx examples, and avoid running the installer against shared or untrusted skill directories.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
install.sh:63
Finding
Shell Installer Follows a Pre-Existing Destination Symlink and Recursively Deletes Its .git Directory<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:63-68` **Vulnerability Type**: Symlink traversal with unsafe recursive deletion **Risk Level**: Medium ### Vulnerable Code ```bash install_to() { mkdir -p "$1/$SKILL_NAME" cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/" rm -rf "$1/$SKILL_NAME/.git" echo "installed -> $1/$SKILL_NAME" } ``` ### Technical Analysis The installer assumes that `$1/$SKILL_NAME` is an ordinary directory under the selected installation destination. It does not inspect the existing path with `lstat`, resolve it to a canonical path, or verify that the resolved target remains beneath the user-selected directory. If an attacker can create `yotta-workflow` as a symbolic link inside a shared or attacker-controlled destination, `cp -r` can write through that link into another writable directory. The subsequent `rm -rf` operation then removes `.git` under the linked destination. Shell quoting prevents ordinary argument-based command injection, but it does not prevent filesystem redirection through a pre-existing symlink. The recursive deletion is particularly risky because it is performed without canonical containment validation. ### Attack Path 1. An attacker obtains write access to a skill directory that the victim will use, such as a shared project-level agent directory. 2. The attacker creates a symlink: ```text <skills-directory>/yotta-workflow -> <writable-victim-directory> ``` 3. The victim runs: ```bash bash install.sh --dir <skills-directory> ``` 4. `mkdir -p` accepts the existing symlinked path. 5. `cp -r` copies the Skill files through the symlink and overwrites matching files in the victim directory. 6. `rm -rf "<skills-directory>/yotta-workflow/.git"` resolves beneath the linked directory and deletes the victim directory's Git metadata. Successful exploitation requires the victim process to have write permission to the linked destination. ### Impact Assessment An attacker can redirec ...[truncated 607 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Inspect the destination with `lstat` before writing and refuse symbolic links. 2. Canonicalize both the selected parent and final target using `realpath`. 3. Verify that the canonical final target is strictly contained within the canonical selected parent. 4. Install into a newly created temporary directory under the verified parent and atomically rename it into place. 5. Avoid recursive deletion in an unverified path. If `.git` must be excluded, omit it during copying rather than deleting it afterward. 6. Refuse installation when the destination already exists as an unexpected file type. 7. Add regression tests covering: - A symlinked `yotta-workflow` destination. - A symlinked parent component. - A destination containing `.git`. - Paths containing spaces and traversal components. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
bin/install.js:147
Finding
Node.js Installer Copies Through Pre-Existing Symlinked Destination Directories<![CDATA[ ## Vulnerability Details **File Location**: `bin/install.js:147-163` **Vulnerability Type**: Symlink traversal and destination-containment bypass **Risk Level**: Medium ### Vulnerable Code ```javascript function installTo(dest) { if (!dest || typeof dest !== 'string') throw new UsageError('Destination directory is required'); const target = path.resolve(dest, SKILL_NAME); assertSafeTarget(target); try { fs.mkdirSync(target, { recursive: true }); copyDir(PKG_ROOT, target, COPY_SKIP); if (!fs.existsSync(path.join(target, 'SKILL.md'))) { throw new InstallError('Installed directory is missing SKILL.md'); } } catch (err) { if (err instanceof UsageError || err instanceof InstallError) throw err; throw new InstallError('Cannot install to ' + target + ': ' + err.message); } console.log('installed -> ' + target); return target; } ``` The copy routine invoked above writes directly to destination entries: ```javascript function copyDir(src, dst, skip) { for (const entry of fs.readdirSync(src, { withFileTypes: true })) { if (skip.has(entry.name)) continue; const from = path.join(src, entry.name); const to = path.join(dst, entry.name); try { if (entry.isDirectory()) { fs.mkdirSync(to, { recursive: true }); copyDir(from, to, skip); } else if (entry.isFile()) { fs.copyFileSync(from, to); } } catch (err) { throw new InstallError('Failed to copy ' + from + ' -> ' + to + ': ' + err.message); } } } ``` ### Technical Analysis `assertSafeTarget` performs a lexical comparison against the package source directory, but the installer does not resolve the destination through `fs.realpathSync` or reject symbolic links with `fs.lstatSync`. Consequently, a path that appears lexically safe can resolve to a different filesystem location. A pre-existing symlink at `<dest>/yotta-workflow`, or a symlink in an intermediate destination component, can redirect ...[truncated 1637 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve the selected parent directory with `fs.realpathSync`. 2. Use `fs.lstatSync` to reject a pre-existing final target that is a symbolic link or other unexpected file type. 3. Validate every pre-existing destination component before recursively copying. 4. Compare canonical paths and require the canonical target to remain beneath the canonical selected parent. 5. Create a fresh temporary installation directory with restrictive permissions, populate it, validate it, and atomically rename it. 6. Consider using copy APIs configured not to dereference symbolic links. 7. Add tests for final-target symlinks, intermediate symlinks, nested destination symlinks, and canonical containment. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:150
Finding
Recommended npx Installation Executes an Unpinned Remote Package<![CDATA[ ## Vulnerability Details **File Location**: `README.md:150-162` **Vulnerability Type**: Unpinned remote package execution and supply-chain exposure **Risk Level**: Medium ### Vulnerable Documentation ```text Pick any of the four methods below; the order is the recommended priority. Skill files always come from **npm** (GitHub can be slow without a proxy; npm supports mirrors). ### Method 1: npm one-liner (recommended) ```text # Optional China mirror: npm config set registry https://registry.npmmirror.com npx -y @yottameta/yotta-workflow --agent <agent-name> # install to the agent's default user-level skills dir npx -y @yottameta/yotta-workflow --dir <your-skills-dir> # point to the skills dir itself (e.g. ~/.codex/skills) ``` - `--agent <name>` installs to that agent's default user-level directory; `--list` shows each agent's default directory. - `--dir <path>` installs to the given directory; for agents not in the preset list, point `--dir` at their skills directory. - If the mirror has not synced the new package (404): add `--registry=https://registry.npmjs.org/` (a proxy may be needed in China), or wait for the mirror cache. ``` Equivalent unpinned commands are also documented in `README.zh-CN.md:150-162`. ### Technical Analysis The recommended command invokes `npx -y` without an explicit package version or integrity value. It therefore downloads and executes whichever version the active npm registry currently resolves for `@yottameta/yotta-workflow`. The `-y` option suppresses the interactive installation confirmation. The effective executable payload can consequently change after this repository version has been audited. Advising users to switch to a package mirror creates an additional trust boundary because the executable package is then obtained from that configured registry. No evidence shows that the currently audited package is malicious. The vulnerability is the installation method's inability to bind execution to the rev ...[truncated 1229 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the documented command to a reviewed release, for example: ```bash npx -y @yottameta/yotta-workflow@0.4.1 --agent <agent-name> ``` 2. Publish SHA-256 checksums or npm integrity values through an independently verifiable release channel. 3. Document how users can download, verify, inspect, and run a specific release artifact. 4. Avoid recommending persistent global registry changes. Prefer a per-command registry option when a mirror is necessary. 5. Clearly state that npm and mirror installation execute remotely distributed code with the invoking user's privileges. 6. Use protected publishing credentials, mandatory multi-factor authentication, provenance attestations, and reproducible release automation. 7. Keep the English and Chinese installation instructions synchronized with the hardened procedure. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (40)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents the skill as a runtime workflow/state-management standard for AI agents, centered on storing and updating project state in a .workflow directory across sessions. The supplied code chunk does something materially different: it is an installer utility. Its primary behavior is to parse command-line options, detect target directories, create directories, and copy package contents into agent skill folders. It accesses filesystem locations like ~/.codex/skills, ~/.config/opencode/skills, and project-local skill directories, but it does not implement the described workflow behaviors such as initializing .workflow, persisting project status, recording decisions/tasks, or restoring cross-session state. This is a clear description-behavior mismatch rather than a mere supporting detail.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述的是“工作流状态管理规范”的功能与适用边界,重点在 .workflow 状态落盘、任务/决策记录、跨会话恢复等行为;而提供的代码块并未实现任何状态记录、项目根目录识别、.workflow 维护、任务流水写入或交接锚点管理。相反,它是一个安装器,负责根据参数和环境变量解析不同智能体的技能目录,并将当前技能复制到这些目录中。这属于明显不同的主要用途,并且涉及对用户主目录/配置目录的文件系统写入,这些能力在声明中没有体现。因此描述与代码行为存在实质性不匹配。

Tool Parameter Abuse

High
Category
Tool Misuse
Content
install_to() {
  mkdir -p "$1/$SKILL_NAME"
  cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/"
  rm -rf "$1/$SKILL_NAME/.git"
  echo "installed -> $1/$SKILL_NAME"
}
Confidence
95% confidence
Finding
The script unconditionally executes rm -rf on a path derived from user-controlled input ($1 via --dir or resolved install targets). Although the path is quoted and constrained by appending /$SKILL_NAME/.git, destructive deletion without validating the resolved destination can remove unexpected data if the target path is mis-specified, points to a symlinked tree, or overlaps sensitive locations. In an installer context, this is more dangerous because users may run it with broad filesystem access and trust it to modify only intended skill directories.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The changelog recommends executing `npx -y @yottameta/yotta-workflow` without pinning an exact version, which causes the latest package version to be fetched at runtime. If the package is later compromised, typosquatted, or a malicious release is published, users following the documentation could execute unreviewed code.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The changelog recommends executing `npx -y @yottameta/yotta-workflow` without pinning an exact version, which causes the latest package version to be fetched at runtime. If the package is later compromised, typosquatted, or a malicious release is published, users following the documentation could execute unreviewed code.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```text
# Optional China mirror: npm config set registry https://registry.npmmirror.com
npx -y @yottameta/yotta-workflow --agent <agent-name>      # install to the agent's default user-level skills dir
npx -y @yottameta/yotta-workflow --dir <your-skills-dir>   # point to the skills dir itself (e.g. ~/.codex/skills)
```
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The README instructs users to execute `npx -y @yottameta/yotta-workflow` without pinning a specific package version. This causes installs to fetch whatever version is current at execution time, so a malicious or compromised future release could be executed immediately on user systems with no review. Because this is an installation command in documentation, the skill context increases the risk: users are likely to copy-paste it verbatim.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The `npx -y @yottameta/yotta-workflow --dir <your-skills-dir>` command also omits a pinned version, so users will execute the latest registry-published package at install time. If the package is hijacked, typo-squatted, or a maintainer account is compromised, this becomes a supply-chain execution path. In a skill README, that risk is material because the command is presented as a recommended installation method.

Rp1

Medium
Category
MCP Rug Pull
Confidence
87% confidence
Finding
The upgrade guidance tells users to rerun the unpinned `npx -y @yottameta/yotta-workflow` command, which again executes an arbitrary future package version. This is dangerous because upgrade paths are repeated over time, extending exposure to supply-chain compromise well beyond initial install. The workflow skill context makes this more dangerous since it is intended for broad reuse across many agents and environments.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill describes automatically initializing and continuously writing `.workflow` state files in project directories, but the README does not prominently warn users that project files will be created and modified. In an agent context, implicit file writes can surprise users, pollute repositories, leak sensitive workflow notes into version control, or overwrite existing project conventions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The README instructs users to execute `npx -y @yottameta/yotta-workflow` without pinning a specific package version. This creates a supply-chain risk: the exact code fetched and executed can change over time, and a compromised publisher account or malicious release would be run immediately on the user's machine.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```text
# 可选国内加速:npm config set registry https://registry.npmmirror.com
npx -y @yottameta/yotta-workflow --agent <智能体名称>      # 装到指定智能体默认用户级技能目录
npx -y @yottameta/yotta-workflow --dir <智能体的技能目录>  # 指到技能目录本身(如 ~/.codex/skills)
```

- `--agent <name>` 自动装到该智能体默认用户级目录;`--list` 可查看各智能体默认目录。
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```text
# 可选国内加速:npm config set registry https://registry.npmmirror.com
npx -y @yottameta/yotta-workflow --agent <智能体名称>      # 装到指定智能体默认用户级技能目录
npx -y @yottameta/yotta-workflow --dir <智能体的技能目录>  # 指到技能目录本身(如 ~/.codex/skills)
```

- `--agent <name>` 自动装到该智能体默认用户级目录;`--list` 可查看各智能体默认目录。
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This command again recommends running an unpinned npm package via `npx`, here with a user-supplied target directory. Because `npx` fetches and executes the latest package by default, users may unknowingly run newly published malicious or compromised code with filesystem write access to skill directories.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The upgrade instructions tell users to rerun the same unpinned `npx` install command. That normalizes repeated execution of mutable remote code and increases exposure to supply-chain compromise during future upgrades, when users are less likely to review what changed.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The statement that the skill should execute automatically without user reminders encourages autonomous activation without a clear consent boundary. That makes the skill more dangerous in context because it is designed to persist information across sessions and could do so even when the user did not intend durable storage or workflow enforcement.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger conditions are very broad ('project', 'resume', 'write to disk', 'multi-step development', 'state changes', 'cross-agent collaboration') and can cause the skill to activate in many ordinary conversations. In practice this can push the agent into unsolicited persistence behavior, increasing the chance of inappropriate file creation, accidental state capture, or overriding user expectations about when durable records are kept.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill directs the agent to automatically initialize and maintain .workflow files on disk, but does not require a prominent user warning or consent before the first write. This is risky because it creates persistent artifacts in a project directory and may record sensitive project state, paths, decisions, or work logs without the user's clear awareness.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The default prompt automatically invokes the workflow skill at session start using a broad phrase without any explicit trigger conditions, user consent check, or scope limitation. This can cause the agent to read and persist project state by default in contexts where the workflow is unnecessary, increasing the risk of unintended file access, state carryover, and prompt-surface expansion across sessions or projects.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

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