Back to skill

Security audit

SkillHub/ClawHub 技能发布

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its publishing purpose, but it can publish or update marketplace content with stored credentials without an enforced confirmation step.

Install only if you are comfortable letting this skill use your existing SkillHub account to publish, update, list, and delete skills. Run dry-run and preflight first, confirm the exact files, slug, version, host, and destination account before any live publish, and avoid --host unless it is the trusted SkillHub API endpoint. Do not run the optional curl-to-bash installer without verifying the source.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/publish.py:1017
Finding

Marketplace publication lacks executable confirmation and preflight enforcement

Content
View full analysis

Vulnerability Details

File Location: scripts/publish.py:950, 1017, 1074-1084; related requirement at SKILL.md:267-268
Vulnerability Type: Unconfirmed external publication using stored account credentials
Risk Level: Medium

Code Snippet

python
creds, err = load_creds(host_override)
if not creds:
    print(json.dumps({"success": False, "error": err}, ensure_ascii=False, indent=2))
    return 1
token, host = creds
python
for attempt in range(max_retry):
    last_status, last_body = post_publish(host, token, payload, files)
    if last_status == 429:
        ra = last_body.get("retryAfter") or delay
        try:
            ra = int(ra)
        except Exception:
            ra = delay
        print(f"  [429] 限流,等待 {ra}s({attempt+1}/{max_retry})",
              file=sys.stderr, flush=True)
        time.sleep(ra)
        delay = min(delay * 2, 600)
        continue
    break
python
pp = sub.add_parser("publish", help="发布/更新")
pp.add_argument("dir")
pp.add_argument("--version", default="")
pp.add_argument("--changelog", default="")
pp.add_argument("--icon", "--cover", dest="icon", default=None,
                help="图标/封面图片(png/jpg/webp,≤2MB)。走 skill-icons/upload 上传")
pp.add_argument("--slug", default="")
pp.add_argument("--host", default=None)
pp.add_argument("--dry-run", action="store_true")
pp.add_argument("--force", action="store_true", help="跳过版本递增检查")

The corresponding Skill instructions state:

markdown
1. **绝不在回复中打印、展示或记录 token**(`skh_` / `gho_` / `ghp_` 开头一律脱敏)。
2. 发布前必须跑预检、必须获得用户确认。

Technical Analysis

The Skill documentation requires both preflight validation and user confirmation before publication. However, the executable entry point does not enforce either requirement. The publish subcommand only distinguishes a dry run from a real publication; it has no mandatory confirmation parameter, confirmation to ...[truncated 2063 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require a dedicated confirmation argument such as --yes-publish for every non-dry-run publication and reject the operation when it is absent.
  2. Run preflight.py --json internally before loading credentials or performing network requests, and block publication when preflight reports an error.
  3. Before confirmation, display the destination host, authenticated account, slug, version, icon, category, complete upload file list, and total size.
  4. Consider requiring confirmation data bound to the reviewed publication plan, such as a digest of the final file bundle and metadata, so modifications after review invalidate approval.
  5. Keep --dry-run as the default behavior for agent-driven workflows and permit live publication only after explicit user authorization.
  6. Document that changing --host changes the credential recipient, and include the resolved host in the mandatory confirmation summary.
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (50)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill claims to provide a full publishing workflow across multiple platforms, but the finding indicates the implemented behavior is limited to unauthorized probing/diagnostic requests for SkillHub WAF 566 classification. This mismatch is dangerous because users and agents may trust it with publication tasks or credentials under false assumptions, while the actual behavior may perform different network actions than advertised.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 26)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 69)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 77)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 86)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 111)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 112)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 132)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 133)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 134)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 135)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 194)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 221)May include surrounding context.

md
| `不支持的文件类型: xxx` | 包内容 | 用 `scripts/publish.py` 发(它按白名单自动过滤) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

md
| `字段格式校验` 类 | 包内容 | 跑 `scripts/preflight.py` 查 frontmatter |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 56)May include surrounding context.

md
| `字段格式校验` 类 | 包内容 | 跑 `scripts/preflight.py` 查 frontmatter |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 57)May include surrounding context.

md
| `字段格式校验` 类 | 包内容 | 跑 `scripts/preflight.py` 查 frontmatter |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 220)May include surrounding context.

md
| `字段格式校验` 类 | 包内容 | 跑 `scripts/preflight.py` 查 frontmatter |

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · SKILL.md (reported line 221)May include surrounding context.

md
| 文件 | 什么时候读 |
|---|---|
| `scripts/preflight.py` | Step 1;发布前必跑 |
| `scripts/publish.py` | Step 2-6;日常发布主入口(含 status / compare / mine / rm / categories) |
| `scripts/waf_bisect.py` | 出现 566 / Failed to fetch 时定位根因 |
| `references/waf-details.md` | 需要理解 WAF 命中特征、判据原理与规避写法时 |
| `references/icon-upload.md` | 要传图标/封面,或怀疑图标没生效(`iconAuditStatus: null`)时 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 246)May include surrounding context.

md
1. **白名单**:只收 `SKILL.md` / `manifest.yaml` / `scripts/*.py`。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 261)May include surrounding context.

md
1. **白名单**:只收 `SKILL.md` / `manifest.yaml` / `scripts/*.py`。

External Script Fetching

High
Category
Supply Chain
Confidence
98% confidence
Finding

This is a concrete instance of external script fetching and immediate execution from a remote source. In the context of a developer-facing publishing skill, users are likely to run the command verbatim, so any compromise of the remote installer or distribution bucket can result in full workstation compromise and downstream credential theft.

Content

Scanner excerpt · references/cli-install.md (reported line 12)May include surrounding context.

bash
# 官方引导脚本(会拉 COS 上的 kit 包)
curl -fsSL https://skillhub.cn/install/install.sh | bash -s -- --cli-only

Windows 直接可用,不必 WSL —— kit 核心是纯 Python 的 skills_store_cli.py(约 226KB),

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The file reveals that authentication tokens are stored in a predictable plaintext location (~/.skillhub/credentials.json), which is sensitive operational detail for any local compromise, malware, or accidental exposure scenario. While documenting storage is not malicious by itself, normalizing plaintext token storage without hardening guidance increases the risk of credential theft and unauthorized publishing actions.

Content

Scanner excerpt · references/cli-install.md (reported line 52)May include surrounding context.

md
1. 浏览器 https://skillhub.cn/dashboard/keys → **创建 API key** → 一次性显示 `skh_xxx`(**只显示一次**)。
2. `skillhub login --key skh_xxx --host https://api.skillhub.cn` → `✓ Logged in as @handle`。
3. `skillhub auth whoami` 验证(端点 `GET /api/v1/auth/me`)。
4. Token 落盘在 `~/.skillhub/credentials.json`,结构为 `{"user": {"token": "...", "host": "..."}}`。

## CLI 的目录收集 vs 服务端白名单(**必踩的坑**)

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Referencing ~/.git-credentials in operational guidance encourages interaction with a file that may contain reusable GitHub secrets. In an agent skill, this materially raises the risk of credential discovery, accidental disclosure, or unauthorized reuse beyond the stated SkillHub publishing purpose.

Content

Scanner excerpt · references/github-repo.md (reported line 30)May include surrounding context.

凭据:gh auth login(2026-09-19 起已登录,此前结论已废)

旧结论作废:本文档曾写「gh CLI 没登录,token 只在 ~/.git-credentials」。 2026-09-19 已完成 gh auth login(device flow),现状态:

bash

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/github-repo.md (reported line 35)May include surrounding context.

bash
gh auth status
# ✓ Logged in to github.com account oracis (keyring), scopes: gist, read:org, repo

gh 不读 git 的 http.proxy 配置,所以任何 gh 联网命令前必须显式给代理,

Static analysis

No suspicious patterns detected.