Back to skill

Security audit

cli-skill-release

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent release helper, but it needs review because its validation can execute other skills' code and one dry-run publish path can still call the ClawHub publisher.

Use this only on repositories and skills you trust, or run it inside a disposable sandbox with no sensitive environment variables. Avoid inventory/recheck over unknown third-party skills, review diffs before release/publish, and do not rely on publish --clawhub --dry-run until that path is fixed.

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

Error
Location
releaser.py:690
Finding

Untrusted Skill Code Is Executed During Validation and Inventory Scans

Content
View full analysis

Vulnerability Details

File Location: releaser.py:690-691, releaser.py:839-850, releaser.py:961-962, and releaser.py:1821
Vulnerability Type: Arbitrary code execution during inspection of untrusted Skills
Risk Level: High

Complete Code Snippets

The validation flow executes the target Skill's selected entry point:

python
r = subprocess.run([sys.executable, main, "doctor", "--path", "."],
                   cwd=skill_dir, capture_output=True, text=True, env=env)

The functional checks import the target module and launch its entry point:

python
mod = os.path.splitext(os.path.basename(entry))[0]
# 2) import entry module
r = _run([sys.executable, "-c", "import %s" % mod], cwd=skill_dir, timeout=25)
if r.returncode == 0:
    _add("PASS", "Entry module can be imported", "", W["fn_import"])
else:
    _add("FAIL", "Entry module import failed",
         (r.stderr or r.stdout).strip()[-200:], W["fn_import"])

# 3) --help smoke test
r = _run([sys.executable, entry, "--help"], cwd=skill_dir, timeout=25)
if r.returncode == 0:
    _add("PASS", "Entry --help smoke test passed", "", W["fn_smoke"])
else:
    _add("WARN", "Entry --help smoke test failed",
         (r.stderr or r.stdout).strip()[-160:], W["fn_smoke"])

The bulk inventory operation also invokes each discovered Skill's entry point:

python
if main:
    env = dict(os.environ)
    env["RELEASER_VALIDATE_DEPTH"] = "1"
    r = subprocess.run([sys.executable, main, "doctor", "--path", "."],
                       cwd=d, capture_output=True, text=True, env=env)
    doc_ok = "Y" if r.returncode == 0 else "N"

The lifecycle recheck operation reaches the same validation execution path:

python
fails = validate_skill(path, mode="skill", silent=True)

Technical Analysis

The project presents validate, gate, inventory, and recheck as inspection and governance features, but these operations do not remain static. They execute Python source controlled by the aut ...[truncated 3263 chars]

Remediation
View remediation

Remediation Suggestions

  1. Make all normal validation, inventory, and lifecycle checks static-only. Parse source with ast and inspect metadata without importing modules or launching target entry points.
  2. Remove automatic execution from bulk inventory and recheck operations. These commands should never execute every discovered Skill merely to determine readiness.
  3. Place dynamic smoke tests behind an explicit option such as --execute-untrusted, accompanied by a clear warning that target code will run.
  4. Run any authorized dynamic checks in a disposable sandbox or container with:
    • a dedicated unprivileged user;
    • no inherited environment variables or credentials;
    • networking disabled by default;
    • the target mounted read-only;
    • a fresh temporary working directory;
    • no access to SSH agents, cloud metadata, home directories, or host sockets; and
    • strict process, CPU, memory, filesystem, and execution-time limits.
  5. Perform static secret and policy checks before any optional dynamic execution. This ordering reduces exposure but does not replace isolation.
  6. Add enforced timeouts to every subprocess, including both doctor calls. On timeout, terminate the complete process group rather than only the immediate child.
  7. Document the distinction between static validation and explicitly authorized dynamic testing so users can make an informed trust decision.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (70)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
84% confidence
Finding

The skill includes a documented capability to perform git add/commit locally and, with explicit flags, git push and clawhub publish. Even though the operation is opt-in, this is still a powerful write action to external systems; if a user is socially engineered or the agent invokes the command without sufficiently clear confirmation, it could publish unintended code or leak sensitive repository contents.

Content

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

bash
python releaser.py release --path .                 # default: local commit + print manual import steps (no push, no publish)
python releaser.py release --path . --dry-run        # generate import steps only, no commit
python releaser.py release --path . --push           # explicit: git push to remote
python releaser.py release --path . --publish        # explicit: publish via your logged-in clawhub CLI

Safe default: release does not touch the remote by default — it only does a local git add/commit and prints ClawHub manual-import steps (auto-resolving repo URL, Display/Slug, top-3 categories, Topics ≤48). You must explicitly pass --push to git push, or --publish to call clawhub publish (requires clawhub CLI installed and clawhub login done). No remote write happens without your explicit flag.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**本技能的核心是一个真能跑的工具 `releaser.py`**(对标 find-skills++ 的能力矩阵):

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**本技能的核心是一个真能跑的工具 `releaser.py`**(对标 find-skills++ 的能力矩阵):

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
83% confidence
Finding

This duplicate finding points to the same release interface that supports remote push and publish operations. In a skill context, exposing high-impact flags in a broadly triggered skill is dangerous because accidental or manipulated invocation can convert a benign validation session into repository mutation or public release.

Content

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

bash
python releaser.py release --path .                 # 默认:本地提交 + 打印人工导入步骤(不推送、不发布)
python releaser.py release --path . --dry-run        # 只生成导入步骤,不提交
python releaser.py release --path . --push           # 显式授权:git push 到远端
python releaser.py release --path . --publish        # 显式授权:经本机已登录的 clawhub CLI 发布

安全默认:release 默认不触碰远端——只做本地 git add/commit 并打印 ClawHub 人工导入步骤(自动解析仓库地址、Display/Slug、推荐分类、Topics≤48)。只有你显式加 --push 才会 git push、加 --publish 才会调用 clawhub publish(且要求本机已 npm i -g clawhub 并 clawhub login)。任何远端写入都需要你明确的命令行授权,工具不会静默推送或发布。

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
83% confidence
Finding

This duplicate finding points to the same release interface that supports remote push and publish operations. In a skill context, exposing high-impact flags in a broadly triggered skill is dangerous because accidental or manipulated invocation can convert a benign validation session into repository mutation or public release.

Content

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

bash
python releaser.py release --path .                 # 默认:本地提交 + 打印人工导入步骤(不推送、不发布)
python releaser.py release --path . --dry-run        # 只生成导入步骤,不提交
python releaser.py release --path . --push           # 显式授权:git push 到远端
python releaser.py release --path . --publish        # 显式授权:经本机已登录的 clawhub CLI 发布

安全默认:release 默认不触碰远端——只做本地 git add/commit 并打印 ClawHub 人工导入步骤(自动解析仓库地址、Display/Slug、推荐分类、Topics≤48)。只有你显式加 --push 才会 git push、加 --publish 才会调用 clawhub publish(且要求本机已 npm i -g clawhub 并 clawhub login)。任何远端写入都需要你明确的命令行授权,工具不会静默推送或发布。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `README.md`:用长尾问题做 H2/H3 标题 + 双语,被搜索引擎/ClawHub/GitHub 索引。

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 478)May include surrounding context.

python
"input(", "getpass", "secret_ref", "resolve_secret", "get_secret",
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 561)May include surrounding context.

python
"input(", "getpass", "secret_ref", "resolve_secret", "get_secret",
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 563)May include surrounding context.

python
"input(", "getpass", "secret_ref", "resolve_secret", "get_secret",
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · tests/test_releaser.py (reported line 762)May include surrounding context.

python
"input(", "getpass", "secret_ref", "resolve_secret", "get_secret",
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 479)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 481)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 554)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · releaser.py (reported line 562)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · tests/test_releaser.py (reported line 756)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · tests/test_releaser.py (reported line 758)May include surrounding context.

python
)

# 扫描的文件扩展名(.env 无论扩展名都扫);令牌格式只在代码/配置类文件扫,避免 .md 误伤
SECRET_SCAN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                    ".yml", ".toml", ".txt", ".cfg", ".ini", ".md", ".rst"}
SECRET_TOKEN_EXTS = {".py", ".js", ".ts", ".sh", ".env", ".json", ".yaml",
                     ".yml", ".toml", ".txt", ".cfg", ".ini"}

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
84% confidence
Finding

The validator copies the full ambient environment into a subprocess that executes untrusted target code. If that child process is malicious, it gains access to sensitive environment variables such as API keys, tokens, and CI secrets, turning validation into credential exposure in addition to code execution.

Content

Scanner excerpt · releaser.py (reported line 688)May include surrounding context.

python
elif not main:
        _add("WARN", "未找到带 doctor 子命令的 CLI 入口(CI 无法跑自检门)", "", W["doctor"])
    else:
        env = dict(os.environ)
        env["RELEASER_VALIDATE_DEPTH"] = "1"
        r = subprocess.run([sys.executable, main, "doctor", "--path", "."],
                           cwd=skill_dir, capture_output=True, text=True, env=env)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
84% confidence
Finding

Inventory mode inherits and passes the full process environment when executing discovered skills. Because scanned skills are untrusted content, this can leak CI tokens, cloud keys, or developer credentials to malicious local skill code during what appears to be a routine audit.

Content

Scanner excerpt · releaser.py (reported line 959)May include surrounding context.

python
main = find_main_entry(d, fm.get("slug") or name)
            doc_ok = "-"
            if main:
                env = dict(os.environ)
                env["RELEASER_VALIDATE_DEPTH"] = "1"
                r = subprocess.run([sys.executable, main, "doctor", "--path", "."],
                                   cwd=d, capture_output=True, text=True, env=env)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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 · releaser.py (reported line 1292)May include surrounding context.

python
if dry_run:
        is_git = os.path.isdir(os.path.join(d, ".git"))
        note = "" if is_git else "(当前非 git 仓库,正式运行需先 `git init` + 配置 origin)"
        return True, "[dry-run] 将:git add -A → commit → git push %s %s%s" % (
            remote, branch, " --force-with-lease" if force else "") + note
    is_git = os.path.isdir(os.path.join(d, ".git"))
    if not is_git:

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

publish --dry-run --clawhub still calls _clawhub_publish without honoring dry-run, so a user expecting a harmless preview can trigger a real external publication. For release tooling, violating dry-run semantics is high risk because it can leak code, metadata, or unfinished artifacts to a public marketplace unintentionally.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

python releaser.py release --path . --push # explicit: git push to remote python releaser.py release --path . --publish # explicit: publish via your logged-in clawhub CLI

text
**Safe default**: `release` does **not** touch the remote by default — it only does a local `git add/commit` and prints ClawHub manual-import steps (auto-resolving repo URL, Display/Slug, top-3 categories, Topics ≤48). You must explicitly pass `--push` to `git push`, or `--publish` to call `clawhub publish` (requires `clawhub` CLI installed and `clawhub login` done). No remote write happens without your explicit flag.
> **Honest note**: ClawHub has no public REST/web publish endpoint (can't proxy OAuth), so the web "Publish" button still needs your login session to click once; `--publish` is the legal explicit path when the `clawhub` CLI is installed and logged in. Faster than competitors' "read the doc and click yourself" by an order of magnitude.

### 2.7.1 secretscan — ★security red-line: kill "things that shouldn't go to GitHub"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill describes capabilities that can read/write files, access environment data, invoke shell commands, and perform network-adjacent publishing actions, but it declares no explicit tool scope or permission boundary in the manifest. That mismatch is dangerous because a host may invoke the skill without a clear least-privilege contract, increasing the chance of unintended repo modification, credential exposure, or remote publication when the skill is triggered.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The natural-language invocation guidance uses many broad phrases like '构建/发布技能', 'CI 一直红', and '零依赖 Python 工具', which overlap with common support requests outside this skill's narrow scope. In context, this is risky because the skill also describes file, shell, and publishing operations, so accidental activation could lead to repo changes or release actions in response to generic troubleshooting prompts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest trigger list includes very broad terms such as '技能', '发布', 'CI', and '工具', which can match many ordinary conversations unrelated to release engineering. Overbroad triggers are dangerous because they can cause the agent to invoke a high-capability skill in the wrong context, exposing local repositories or causing unintended modification/publish workflows.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This Python file is a code file, so SQP-3 applies to natural-language strings embedded in code. The primary docstring and many CLI messages are written in Chinese only, which imposes a language/locale choice on users without any opt-in or alternative locale support.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
tests/test_releaser.py:717