Back to skill

Security audit

git-sync

Security checks for vulnerabilities and agentic risk

Overview

This is a real publishing automation skill, but it has unsafe path, command, and persistent Git credential handling that should be reviewed before installation.

Install only if you are comfortable giving this skill authority to modify local repositories, push and publish externally, read local Git/PyPI/Gitee credentials, and change Git credential configuration. Review and constrain config.json and manifest.json before use, avoid untrusted projects, and prefer a patched version that removes shell=True, validates destination paths, avoids global credential.helper changes, and pins external CLIs.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/git-sync.py:1321
Finding
Shell Command Injection Through ClawHub Publication Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/git-sync.py:1321-1326` **Vulnerability Type**: OS command injection through untrusted metadata and `shell=True` **Risk Level**: Critical ### Vulnerable Code ```python def step_clawhub_publish(name: str, version: str): # v2.37.0 多仓库:skill 仓库根下直接是技能目录 sd = get_work_repo("skill") / name if not sd.is_dir(): print(" ❌ 技能目录不存在"); return meta = json.loads((sd/"_meta.json").read_text(encoding="utf-8")) slug = meta.get("slug",name) cmd = f'npx clawhub publish "{sd}" --slug "{slug}" --name "{meta.get("displayName",name)}" --version "{version}" --changelog "v{version}"' if meta.get("tags"): cmd += ' --tags "' + ",".join(meta["tags"]) + '"' r = subprocess.run(cmd, capture_output=True, text=True, shell=True) ``` ### Technical Analysis The command is assembled as one shell command string and then executed with `shell=True`. Several interpolated values originate from the project’s `_meta.json` file: - `slug` - `displayName` - `tags` Wrapping those values in double quotes does not make them safe. An attacker can include a quotation mark followed by shell metacharacters to terminate the intended argument and append another command. The exact metacharacters vary by operating system, but the flaw applies to both POSIX shells and Windows command processors. The project already contains a safer implementation in `scripts/clawhub_publish.py`, where arguments are passed as a list. The vulnerable integrated implementation does not use that protection. ### Attack Path 1. An attacker supplies or modifies a project that the user intends to publish. 2. The attacker inserts shell syntax into an `_meta.json` field, for example a `displayName` that closes the quoted argument and appends a command. 3. The user invokes the Skill with ClawHub publishing enabled. 4. `step_clawhub_publish()` reads the attacker-controlled metadata. 5. The function interpolates the value into `cmd`. 6. `s ...[truncated 966 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `shell=True` and pass every argument as a separate list element: ```python cmd = [ "npx", "--no-install", "clawhub", "publish", str(sd), "--slug", slug, "--name", meta.get("displayName", name), "--version", version, "--changelog", f"v{version}", ] if meta.get("tags"): cmd.extend(["--tags", ",".join(meta["tags"])]) result = subprocess.run( cmd, capture_output=True, text=True, shell=False, check=False, ) ``` 2. Reuse the argument-list implementation in `scripts/clawhub_publish.py` rather than maintaining a second command-building path. 3. Validate `slug`, `displayName`, tags, project name, and version before command execution: - Impose reasonable maximum lengths. - Require `slug` and project names to match a strict allowlist such as `[A-Za-z0-9._-]+`. - Require tags to be strings and reject control characters. - Validate versions using the expected version grammar. 4. Do not attempt to fix this solely through manual shell escaping. Avoiding shell interpretation is the more reliable control. 5. Add regression tests containing quotation marks, command separators, newlines, substitutions, and platform-specific shell metacharacters. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/git-sync.py:1488
Finding
Manifest-Controlled Destination Path Can Cause Arbitrary Recursive Directory Deletion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/git-sync.py:1488-1495`, with the destructive sink at `scripts/git-sync.py:418-431` and `scripts/git-sync.py:1649-1654` **Vulnerability Type**: Path traversal and unsafe recursive deletion **Risk Level**: Critical ### Vulnerable Code Manifest-derived destination selection: ```python mf = json.load(open(MANIFEST_FILE, encoding="utf-8")) for repo_name, repo_data in mf.get("repos", {}).items(): item = repo_data.get("items", {}).get(name) if item and isinstance(item, dict): mf_src = item.get("source_path", "") mf_repo = item.get("repo_path", "") if mf_src and Path(mf_src).is_dir(): src_dir = Path(mf_src) # v2.37.0 多仓库:repo_path 为仓库根下相对路径(无 skills//agent/ 前缀) work_repo_subdir = mf_repo or name ``` Destructive skill synchronization: ```python def sync_files(skill_name: str, skills_dir: Path, work_repo: Path, allowed_files: set = None, subdir: str = None): """用 Python 逐个复制文件。只复制 allowed_files 集合中的文件(全部保留时传 None) v2.45.0 修复:目标子目录不再硬编码 'skills/' 前缀。 仓库结构由 manifest/config 的 repo_path 决定(顶层或 skills/ 子目录), 调用方通过 subdir 传入;不传时回退到顶层(技能名在仓库根)。 """ src = skills_dir / skill_name dst = work_repo / (subdir or skill_name) if dst.exists(): shutil.rmtree(dst) os.makedirs(dst, exist_ok=True) ``` Destructive agent synchronization: ```python else: dst = WORK_REPO / work_repo_subdir if dst.exists(): shutil.rmtree(dst) os.makedirs(dst, exist_ok=True) ``` ### Technical Analysis The code assumes that `repo_path` is a safe relative path below `WORK_REPO`, but it does not enforce that assumption. With `pathlib`, joining a base path to an absolute path can discard the base path. A relative path containing `..` components can also resolve outside the repository. The resulting path is passed to `shutil.rmtree()` before files are copied. The command-line project name is likewise used in ...[truncated 1617 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `repo_path` to be a non-empty relative path: - Reject absolute paths. - Reject `.` and `..` path components. - Reject empty paths that could resolve to the repository root. 2. Resolve and compare canonical paths before any deletion: ```python repo_root = WORK_REPO.resolve() candidate = (repo_root / work_repo_subdir).resolve() if candidate == repo_root or not candidate.is_relative_to(repo_root): raise ValueError(f"Unsafe repository destination: {candidate}") ``` 3. Repeat the boundary assertion immediately before every recursive deletion. Do not rely only on earlier validation. 4. Validate project names centrally with a strict grammar, such as: ```python if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,127}", name): raise ValueError("Invalid project name") ``` 5. Reject symlinked destinations or explicitly define safe symlink behavior. Recheck the resolved path immediately before deletion to reduce time-of-check/time-of-use risk. 6. Verify that the destination contains an expected repository marker before deleting it. 7. Prefer staging into a newly created directory and performing a controlled replacement rather than deleting an existing destination first. 8. Add tests for absolute paths, `../` traversal, Windows drive paths, UNC paths, repository-root targets, symlinks, and nested traversal. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/git-sync.py:1421
Finding
Every Invocation Persistently Enables Global Plaintext Git Credential Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/git-sync.py:1421-1444` **Vulnerability Type**: Persistent global security configuration change and plaintext credential storage **Risk Level**: High ### Vulnerable Code ```python def main(): # v2.37.0 多仓库:按类型动态切换仓库路径(须在函数内首次使用前声明) global WORK_REPO, README_FILE global QUIET_MODE # ── 0. 彻底阻止 CredentialHelperSelector 弹窗 ────────────────────── # 方案:在最早时机固化 credential.helper 配置,所有后续 git 命令直接继承 # 同时用 GIT_CREDENTIAL_HELPER 环境变量双重保险 import subprocess as _sp _env = os.environ.copy() _env["GIT_TERMINAL_PROMPT"] = "0" # 写入 repo 级配置(最高优先级,覆盖全局) _sp.run( ["git", "config", "credential.helper", "store"], cwd=str(WORK_REPO), capture_output=True, check=False, env=_env ) # 写入全局配置(防止 repo 级失败) _sp.run( ["git", "config", "--global", "credential.helper", "store"], capture_output=True, check=False, env=_env ) # 确保 .git-credentials 文件存在(避免 store helper 报错) _cred = Path.home() / ".git-credentials" if not _cred.exists(): try: _cred.write_text("", encoding="utf-8") except Exception: pass ``` ### Technical Analysis The Skill modifies the user’s global Git configuration on every invocation by setting: ```text credential.helper=store ``` Git’s `store` helper saves credentials in plaintext. The code also creates `~/.git-credentials` if it does not exist. This is not limited to the current subprocess or target repository. The global setting affects later Git commands, unrelated repositories, and future sessions. It therefore exceeds the minimum privileges and persistence required for a single synchronization or publishing operation. The behavior is also internally inconsistent: `run_git()` injects configuration that disables credential helpers, while `main()` persistently enables the plaintext helper globally. ### Attack Path 1. A user runs any supported `git-sync.py` operation ...[truncated 1283 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the global command entirely: ```python ["git", "config", "--global", "credential.helper", "store"] ``` 2. Do not create `~/.git-credentials` automatically. 3. Use only process-scoped Git configuration through environment variables or `git -c` arguments. 4. Prefer an operating-system-backed credential manager: - Git Credential Manager - macOS Keychain - Windows Credential Manager - Secret Service or another secure Linux keyring 5. For CI environments, provide narrowly scoped short-lived tokens through protected environment variables. 6. Never place credentials in remote URLs, because they may appear in process listings, logs, Git configuration files, or error messages. 7. If repository-local configuration is retained, require explicit user consent and restore the previous configuration after the operation. 8. Document credential sources, destinations, storage duration, and token-scope requirements. 9. Add a migration warning that detects an existing globally configured `store` helper but does not overwrite the user’s configuration. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/clawhub_publish.py:43
Finding
Unpinned npx Package Can Retrieve and Execute Changed Third-Party Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawhub_publish.py:43-52` and `scripts/git-sync.py:1321-1326` **Vulnerability Type**: Unpinned executable dependency and supply-chain code execution **Risk Level**: Medium ### Vulnerable Code Standalone publisher: ```python cmd = [ "npx", "clawhub", "publish", skill_dir, "--slug", slug, "--name", display_name, "--version", version, "--changelog", changelog, ] result = subprocess.run(cmd, capture_output=True, text=True, cwd=work_repo) ``` Integrated publisher: ```python slug = meta.get("slug",name) cmd = f'npx clawhub publish "{sd}" --slug "{slug}" --name "{meta.get("displayName",name)}" --version "{version}" --changelog "v{version}"' if meta.get("tags"): cmd += ' --tags "' + ",".join(meta["tags"]) + '"' r = subprocess.run(cmd, capture_output=True, text=True, shell=True) ``` ### Technical Analysis The Skill invokes `npx clawhub` without specifying an exact audited version or requiring a preinstalled local package. Depending on the npm/npx version and local package state, `npx` can retrieve package code from the configured registry and execute it immediately. Consequently, the effective executable may differ from the code reviewed during this audit. A newly published, compromised, or otherwise unexpected `clawhub` package version could execute with the invoking user’s privileges. This finding is separate from the command-injection vulnerability in the integrated publisher. Even after replacing `shell=True`, dynamically resolving an unpinned executable remains a supply-chain risk. ### Attack Path 1. The expected `clawhub` package is not installed locally at a pinned version, or npx otherwise resolves it through the package registry. 2. The package version available from the configured registry changes or is compromised after the Skill was reviewed. 3. The user invokes ClawHub publishing. 4. `npx` resolves and potentially downloads the package. 5. Package installation h ...[truncated 898 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the CLI to an exact reviewed version. 2. Declare it in a package manifest and commit a lockfile containing resolved versions and integrity hashes. 3. Install dependencies during an explicit setup step rather than allowing publication to retrieve and execute code implicitly. 4. Invoke the fixed local executable, or use: ```text npx --no-install clawhub ... ``` 5. If direct npx resolution is unavoidable, specify an exact version and verify package integrity before execution. 6. Review dependency ownership, release history, installation scripts, and transitive dependencies. 7. Use a restricted environment for publication: - Minimal filesystem access. - Narrowly scoped tokens. - No unrelated secrets in the environment. - Network access limited to required publication endpoints where practical. 8. Add dependency-update automation that requires review before changing the pinned version or lockfile. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (130)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation performs destructive destination deletion before copy and this behavior is omitted from the description, that is a real safety issue for a file-writing automation skill. Undisclosed destructive operations can cause data loss or overwrite unintended content, especially when combined with broad triggers and shell/file-write capabilities.

Ae1

High
Category
analysis-evasion
Content
> 📚 **渐进式加载**:本技能采用渐进式 MD 体系,`SKILL.md` 为入口(≤230行),详细内容拆分到 `references/*.md` 按需加载。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
> 📚 **渐进式加载**:本技能采用渐进式 MD 体系,`SKILL.md` 为入口(≤230行),详细内容拆分到 `references/*.md` 按需加载。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
> 📚 **渐进式加载**:本技能采用渐进式 MD 体系,`SKILL.md` 为入口(≤230行),详细内容拆分到 `references/*.md` 按需加载。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
> ⚠️ **执行入口**:环境无 `rsync` 时(如部分 Windows Git 环境),`git-sync.sh` 会自动切换到 Python 完整流程。**直接调用 `python git-sync.py` 与 `bash git-sync.sh` 效果相同**,推荐直接使用 Python 入口。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Vague Triggers

High
Confidence
97% confidence
Finding
The trigger phrase list is broad and combines common actions like sync, push, publish, upload, package, update README into a single activation pattern, making accidental invocation likely during unrelated user requests. Because this skill performs multi-platform repository sync and release actions, unintended activation could cause unauthorized publication, repository changes, or disclosure of files to external services.

Credential Access

High
Category
Privilege Escalation
Content
### Q3: Gitee push 需要密码但 PAT 仅限 API?

Gitee 的 PAT(Personal Access Token)通常仅限 API 操作,git push 需要登录密码或 SSH key。API 操作(如 Release 创建)使用 `config.json` 的 `gitee_token` 字段。

解决方案:
1. 使用 SSH 方式配置 Gitee remote(推荐)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
先删除临时文件再执行同步:

```bash
rm -f $SKILLS_DIR/<skill-name>/*.html
```

或在 skill 目录下添加 `.gitignore` 规则排除 html。
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).

Env Variable Harvesting

High
Category
Data Exfiltration
Content
用 GIT_CONFIG_COUNT 注入 credential.helper=(空=禁用),
    优先级高于所有配置文件,覆盖所有子进程(含 Python 脚本内调 git)。
    """
    env = base_env.copy() if base_env else os.environ.copy()
    env["GIT_TERMINAL_PROMPT"] = "0"
    env["GIT_CONFIG_COUNT"] = "1"
    env["GIT_CONFIG_KEY_0"] = "credential.helper"
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
用 GIT_CONFIG_COUNT 注入 credential.helper=(空=禁用),
    优先级高于所有配置文件,覆盖所有子进程(含 Python 脚本内调 git)。
    """
    env = base_env.copy() if base_env else os.environ.copy()
    env["GIT_TERMINAL_PROMPT"] = "0"
    env["GIT_CONFIG_COUNT"] = "1"
    env["GIT_CONFIG_KEY_0"] = "credential.helper"
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
用 GIT_CONFIG_COUNT 注入 credential.helper=(空=禁用),
    优先级高于所有配置文件,覆盖所有子进程(含 Python 脚本内调 git)。
    """
    env = base_env.copy() if base_env else os.environ.copy()
    env["GIT_TERMINAL_PROMPT"] = "0"
    env["GIT_CONFIG_COUNT"] = "1"
    env["GIT_CONFIG_KEY_0"] = "credential.helper"
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Static analysis

No suspicious patterns detected.