Back to skill

Security audit

agent-skill-manager

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it has high-impact filesystem and repository-changing behavior with weak scoping that users should review before installing.

Review this before installing. Use it only in a disposable or backed-up environment until remove/install path validation is fixed, avoid --sync for remote URLs, run audits before distributing skills to agent products, and remove the unrelated add-contributor scripts from the package if they are not intentionally needed.

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

T09 · Insecure Skill Coding Practices

Error
Location
src/services/sync.py:374
Finding
Path Traversal Allows Recursive Deletion Outside Managed Skill Directories<![CDATA[ ## Vulnerability Details **File Location**: `src/controllers/cli.py:228-232`; `src/services/sync.py:374-415` **Vulnerability Type**: Unvalidated path component used in recursive filesystem deletion **Risk Level**: High ### Vulnerable Code ```python # src/controllers/cli.py:228-232 elif command == "remove": if len(sys.argv) < 3: print("Usage: askill remove <skill-name>") return _print_remove(sys.argv[2]) ``` ```python # src/services/sync.py:374-415 def remove_skill(skill_name: str, verbose: bool = True) -> list[str]: """Remove a skill from central repo and all products.""" skill_dir = CENTRAL_DIR / skill_name if not skill_dir.exists(): if verbose: print(f"Skill not found in central repo: {skill_name}") return [] removed = [] for p in PRODUCTS: if p["sync_method"] in ("native", "pack"): continue target = get_product_path(p) if target is None: continue link_path = target / skill_name if link_path.exists() or link_path.is_symlink(): remove_path(link_path) removed.append(p["short"]) for d in get_all_product_dirs(p)[1:]: link_path = d / skill_name if link_path.exists() or link_path.is_symlink(): remove_path(link_path) removed.append(f"{p['short']}-alt") if p.get("settings_file"): _remove_from_workbuddy_settings( p["settings_file"], skill_name, removed, verbose=verbose ) shutil.rmtree(skill_dir) removed.append("central") ``` The deletion helper can recursively remove ordinary directories: ```python # src/utils/filesystem.py:122-135 def remove_path(path: Path) -> None: path = Path(path) if not path.exists() and not path.is_symlink(): return if is_symlink_or_junction(path): path.rmdir() elif path.is_dir(): shutil.rmtree(path) else ...[truncated 2306 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict skill names to one safe path component using a strict allowlist, for example: ```python import re SKILL_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$") def validate_skill_name(name: str) -> str: if not SKILL_NAME_RE.fullmatch(name): raise ValueError("Invalid skill name") if name in {".", ".."}: raise ValueError("Invalid skill name") return name ``` 2. Reject absolute paths and path separators explicitly: ```python candidate = Path(skill_name) if candidate.is_absolute() or len(candidate.parts) != 1: raise ValueError("Skill name must be a single path component") ``` 3. Before every removal, resolve the candidate and verify containment under the expected root: ```python def contained_path(root: Path, name: str) -> Path: root = root.resolve() candidate = (root / name).resolve(strict=False) if candidate.parent != root: raise ValueError("Path escapes managed root") return candidate ``` 4. Apply containment checks independently to the central directory, each product directory, and every alternate directory. 5. Confirm that the central target contains a regular `SKILL.md` before treating it as a removable skill. 6. Add regression tests covering `../x`, `../../x`, absolute paths, platform-specific separators, symlink edge cases, and paths sharing only a textual prefix with the managed root. ]]>

T08 · Insecure Dependencies

Warning
Location
src/services/sync.py:233
Finding
Bypassable Remote Repository Validation and Synchronization Before Security Audit<![CDATA[ ## Vulnerability Details **File Location**: `src/services/sync.py:233-246`, `src/services/sync.py:285-362` **Vulnerability Type**: Unsafe remote-source validation and insecure installation workflow **Risk Level**: Medium ### Vulnerable Code ```python # src/services/sync.py:233-246 if source.startswith("http"): name, ok = _install_from_url(source, verbose=verbose) else: name, ok = _install_from_local(source, verbose=verbose) if ok and sync and name: if verbose: print() sync_skill(name, verbose=verbose) if ok and audit and name: if verbose: print() print(f"Running security audit on {name}...") audit_skill(name, verbose=verbose) ``` ```python # src/services/sync.py:285-298 def _install_from_url(source: str, verbose: bool = True) -> tuple[str | None, bool]: """Install skill from a GitHub URL.""" if verbose: print(f"Installing from URL: {source}") if "github.com" not in source: if verbose: print("Unsupported URL format. Use a GitHub URL.") return None, False ``` ```python # src/services/sync.py:341-362 with tempfile.TemporaryDirectory() as tmp: try: cmd = ["git", "clone", "--depth", "1"] if branch: cmd += ["--branch", branch] cmd += [repo_url, tmp] subprocess.run( cmd, check=True, capture_output=True, text=True, encoding="utf-8", errors="replace", ) if sub_path: src = Path(tmp) / sub_path else: src = Path(tmp) if not src.exists() or not (src / "SKILL.md").exists(): if verbose: print(f"No SKILL.md found in {src}") return None, False shutil.copytree(src, dest) if verbose: print(f"Installed: {dest}") return skill_name, True ``` ### Technical Analysis The code intends to restrict remote installation to GitHub, but validates the source with a s ...[truncated 2788 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse remote URLs with `urllib.parse.urlparse` and require an exact host: ```python from urllib.parse import urlparse parsed = urlparse(source) if parsed.scheme != "https" or parsed.hostname != "github.com": raise ValueError("Only HTTPS GitHub URLs are supported") ``` 2. Reject embedded credentials, unexpected ports, malformed paths, fragments, and ambiguous hostnames: ```python if parsed.username or parsed.password or parsed.port not in (None, 443): raise ValueError("Unsupported URL authority") ``` 3. Clone into quarantine and run the audit before copying content into `CENTRAL_DIR`. 4. Change the workflow to: - Download into a temporary quarantine directory. - Validate structure and canonical paths. - Run the static audit. - Block critical or high-risk findings by default. - Display the source host, owner, repository, branch, and commit. - Require explicit user confirmation before installation. - Synchronize only after approval. 5. Make auditing mandatory for remote sources. The `--audit` option may remain useful for local sources, but remote content should not bypass scanning. 6. Pin imported content to a specific commit and record its source and commit hash to improve provenance and reproducibility. 7. Add tests for deceptive hosts such as `github.com.example.org`, `evilgithub.com`, URLs containing `github.com` in the path or user-information field, non-HTTPS schemes, and synchronization attempts involving a failed audit. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (87)

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
C%20Windows-0078D4?logo=windows&logoColor=white)](https://github.com/yxdwind/agent-skill-manager)
[![License](https://img.shields.io/badge/License-MIT-22c55e?logo=opensourceinitiative&logoColor=white)](LICENSE)
[![Products](https://img.shields.io/badge/Products-11%20supported-8b5cf6)](#supported-products)

**Write once, sync everywhere** — Cross-platform skill management for 11 domestic Chinese AI agent products.

[Install](#install) · [Usage](#usage) · [Security Audit](#security-audit) · [Architecture](#architecture)

</div>

---

## The Problem

Every Chinese AI agent product keeps its skills in its own directory. Developing one skill means manually copying it to every product:

```
~/.openclaw/skills/my-skill/          <- AutoClaw
~/.config/agents/skills/my-skill/     <- Kimi
~/.workbuddy/skills/my-skill/         <- WorkBuddy
~/.trae/skills/my-skill/              <- Trae
~/.codebuddy/skills/my-skill/         <- CodeBuddy
~/.comate/skills/my-skill/            <- Comate
~/.qoderw
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| Dimension | Severity | Examples |
|-----------|----------|----------|
| Prompt injection | critical | "ignore all previous instructions", safety bypass language |
| Dangerous code | critical/high | `curl \| sh`, `rm -rf /`, `exec()`, `shell=True` |
| Secrets & exfiltration | high/medium | reading `~/.ssh`, hardcoded API keys, webhook URLs |
| Binary files | high | bundled `.exe`/`.dll` executables |
| File integrity | high/medium | missing SKILL.md, oversized files, symlinks |
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
ge/License-MIT-22c55e?logo=opensourceinitiative&logoColor=white)](LICENSE)
[![CI](https://github.com/yxdwind/agent-skill-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/yxdwind/agent-skill-manager/actions/workflows/ci.yml)
[![Products](https://img.shields.io/badge/Products-11%20supported-8b5cf6)](#支持的产品)

**一次开发,十一端同步** — 跨平台统一管理国内 AI Agent 产品的 Skill 安装与同步

[安装](#安装) · [使用](#使用) · [二次开发](#二次开发) · [架构原理](#架构原理)

</div>

---

## 痛点

每个国产 AI Agent 产品都有自己独立的 skill 目录,开发一个 skill 要手动复制到每个产品:

```
~/.openclaw/skills/my-skill/          ← AutoClaw
~/.config/agents/skills/my-skill/      ← Kimi
~/.workbuddy/skills/my-skill/          ← WorkBuddy
~/.trae/skills/my-skill/               ← Trae
~/.codebuddy/skills/my-skill/          ← CodeBuddy
~/.comate/skills/my-skill/             ← Comate
~/
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Instruction Override

High
Category
Prompt Injection
Content
| 检测维度 | 严重级别 | 示例 |
|---------|---------|------|
| 提示注入 | critical | "ignore all previous instructions"、绕过安全护栏指令 |
| 危险代码 | critical/high | `curl \| sh`、`rm -rf /`、`exec()`、`shell=True` |
| 敏感信息 | high/medium | 读取 `~/.ssh`、硬编码 API key、webhook 外发 |
| 二进制文件 | high | .exe/.dll 等可执行文件混入 skill |
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Instruction Override

High
Category
Prompt Injection
Content
| 检测维度 | 严重级别 | 示例 |
|---------|---------|------|
| 提示注入 | critical | "ignore all previous instructions"、绕过安全护栏指令 |
| 危险代码 | critical/high | `curl \| sh`、`rm -rf /`、`exec()`、`shell=True` |
| 敏感信息 | high/medium | 读取 `~/.ssh`、硬编码 API key、webhook 外发 |
| 二进制文件 | high | .exe/.dll 等可执行文件混入 skill |
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

External Script Fetching

High
Category
Supply Chain
Content
| 检测维度 | 严重级别 | 示例 |
|---------|---------|------|
| 提示注入 | critical | "ignore all previous instructions"、绕过安全护栏指令 |
| 危险代码 | critical/high | `curl \| sh`、`rm -rf /`、`exec()`、`shell=True` |
| 敏感信息 | high/medium | 读取 `~/.ssh`、硬编码 API key、webhook 外发 |
| 二进制文件 | high | .exe/.dll 等可执行文件混入 skill |
| 文件完整性 | high/medium | 缺少 SKILL.md、超大文件、符号链接 |
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
| 检测维度 | 严重级别 | 示例 |
|---------|---------|------|
| 提示注入 | critical | "ignore all previous instructions"、绕过安全护栏指令 |
| 危险代码 | critical/high | `curl \| sh`、`rm -rf /`、`exec()`、`shell=True` |
| 敏感信息 | high/medium | 读取 `~/.ssh`、硬编码 API key、webhook 外发 |
| 二进制文件 | high | .exe/.dll 等可执行文件混入 skill |
| 文件完整性 | high/medium | 缺少 SKILL.md、超大文件、符号链接 |
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| 检测维度 | 严重级别 | 示例 |
|---------|---------|------|
| 提示注入 | critical | "ignore all previous instructions"、绕过安全护栏指令 |
| 危险代码 | critical/high | `curl \| sh`、`rm -rf /`、`exec()`、`shell=True` |
| 敏感信息 | high/medium | 读取 `~/.ssh`、硬编码 API key、webhook 外发 |
| 二进制文件 | high | .exe/.dll 等可执行文件混入 skill |
| 文件完整性 | high/medium | 缺少 SKILL.md、超大文件、符号链接 |
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

External Script Fetching

High
Category
Supply Chain
Content
- API 密钥或私有内容出现在源码、日志、截图或发布包中;
- skill 内容中的**提示注入(prompt injection)**或指令覆盖,试图绕过 AI 助手的安全护栏;
- skill 内置脚本中的**危险代码**(如 `curl | sh`、`rm -rf /`、`exec()`、读取 `~/.ssh` 等敏感文件);
- skill 未经授权向未知网络端点**外发数据**(webhook、`requests.post` 等);
- 可执行二进制文件(`.exe`/`.dll`)混入 skill 目录;
- 依赖或发布流程被篡改;
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
- API 密钥或私有内容出现在源码、日志、截图或发布包中;
- skill 内容中的**提示注入(prompt injection)**或指令覆盖,试图绕过 AI 助手的安全护栏;
- skill 内置脚本中的**危险代码**(如 `curl | sh`、`rm -rf /`、`exec()`、读取 `~/.ssh` 等敏感文件);
- skill 未经授权向未知网络端点**外发数据**(webhook、`requests.post` 等);
- 可执行二进制文件(`.exe`/`.dll`)混入 skill 目录;
- 依赖或发布流程被篡改;
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- API 密钥或私有内容出现在源码、日志、截图或发布包中;
- skill 内容中的**提示注入(prompt injection)**或指令覆盖,试图绕过 AI 助手的安全护栏;
- skill 内置脚本中的**危险代码**(如 `curl | sh`、`rm -rf /`、`exec()`、读取 `~/.ssh` 等敏感文件);
- skill 未经授权向未知网络端点**外发数据**(webhook、`requests.post` 等);
- 可执行二进制文件(`.exe`/`.dll`)混入 skill 目录;
- 依赖或发布流程被篡改;
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description is for a general-purpose multi-platform skill manager CLI, but the supplied code is unrelated to skill management or syncing across AI products. Instead, it performs repository maintenance and contribution-attribution actions in a hardcoded local repo path, including git fetch/reset, editing README.md, committing, and pushing to GitHub. These are materially different capabilities and resources than declared, so this is a clear mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description claims a concrete cross-platform skill management tool with CLI operations to sync/install/remove skills across multiple products. The provided code chunk, however, is only an `__init__.py` file containing documentation for a controllers layer. It does not implement or demonstrate the declared primary purpose, resource access, or platform integrations. Based on this chunk alone, the actual behavior is merely package/module documentation scaffolding, which is materially different from the declared functionality.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description emphasizes a cross-platform skill management CLI for syncing and managing skills across multiple AI products. The supplied code chunk does not implement skill installation, syncing, removal, or CLI management behavior. Instead, it defines typed report schemas for security-audit findings and status reporting. While status entries referencing products could be tangentially related to a manager, the primary purpose of this code is security audit/report data modeling, which is materially different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The supplied code chunk is minimal and only documents a generic services layer for 'sync' and 'audit'. It does not demonstrate the declared primary purpose of a cross-platform skill manager CLI for 11 AI products, nor does it show installation, removal, syncing across products, or any `askill` command behavior. Additionally, the docstring mentions 'audit', which is not part of the declared description. Based on this chunk alone, the description does not accurately represent the observed behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description says this skill is a cross-platform skill manager/installer/sync tool for multiple AI products. However, the supplied code does not implement installation, syncing, removal, CLI management, or any product-integration behavior. Instead, it performs static analysis and security auditing of skill directories, generating findings and risk scores. This is a materially different primary purpose, not merely an internal helper for a manager, because the code's visible functionality centers on auditing rather than managing or syncing skills.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description promises a full cross-platform skill manager with product integrations and CLI operations. The supplied code chunk does not implement any of that; it merely defines a utils package with a docstring describing filesystem helpers. While this could be a supporting component of such a tool, the actual chunk itself does not match the declared primary purpose or capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description describes a substantial cross-platform CLI tool for managing skills across multiple products. The supplied code chunk, however, is only `tests/__init__.py` containing a comment and no executable logic. This is a material mismatch because the actual code shown does not implement or substantiate the claimed behavior, capabilities, or integrations.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents the skill as a cross-platform manager for syncing and managing skills across multiple AI products. However, the supplied code chunk is specifically a test module focused on CLI output related to security audit scores and risky content labeling. While this may be related to the broader project, the chunk’s actual behavior is not primarily about installing, syncing, or removing skills across platforms. Instead, it validates score/grade presentation and risky-skill detection in command output. That is a materially different primary purpose for this code chunk, so the description does not accurately represent it.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description emphasizes cross-platform skill management and synchronization via a CLI. However, the provided code does not implement management, installation, syncing, or removal behavior. Instead, it tests a security analysis subsystem that inspects skill directories for malicious or risky content and assigns grades/verdicts. Security auditing could be a supporting feature in a larger skill manager, but in this chunk the primary behavior is materially different from the declared purpose, and it exposes significant undeclared capabilities related to static security scanning.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This script is unrelated to the stated purpose of managing or syncing agent skills across products. It performs direct repository manipulation to rewrite local state, modify README content, forge contributor metadata, and push changes upstream, which creates a strong supply-chain and trust-boundary concern inside a skill package that users would expect to manage agent skills rather than alter project history/content.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script fetches from origin, hard-resets to the remote branch, commits changes, and pushes to GitHub, giving it powerful remote repository modification capability that is unjustified for an agent-skill manager. In the skill context, this is especially dangerous because users may invoke the skill expecting local skill synchronization, not source-control operations that can overwrite work and publish unauthorized changes.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo [2/6] 同步到远程最新状态...
git fetch origin
git reset --hard origin/master

echo [3/6] 在 README.md 中添加贡献者区块...
python -c "
Confidence
99% confidence
Finding
'git reset --hard origin/master' is a destructive command that forcibly discards local changes and moves the working tree to match the remote branch. In this skill, its presence is particularly concerning because the command is embedded in automation unrelated to the advertised skill-management purpose, increasing the chance of unexpected data loss and unauthorized repository state changes.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def run(cmd, env=None, check=True):
    print(f"  $ {cmd}")
    result = subprocess.run(cmd, shell=True, env=env, capture_output=True, text=True)
    if result.stdout.strip():
        print(f"    {result.stdout.strip()}")
    if result.stderr.strip():
Confidence
90% confidence
Finding
Using subprocess.run with shell=True is an unsafe tool-parameter choice because it delegates parsing to the shell and enables injection or unexpected command chaining if inputs ever become dynamic. In an agent-skill context, this is more dangerous because such helpers are often reused or extended, turning a latent issue into an execution primitive.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script can reset local repository state, stage files, create commits, and push to a remote branch, granting destructive source-control authority not justified by the skill's stated function. If executed in a user environment, it could overwrite local work and publish unauthorized changes to upstream repositories.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
README.en.md:171

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
README.md:171