Back to skill

Security audit

cjg-skill-sync

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent updater, but its default check writes tracking files into installed skills despite repeatedly describing check mode as read-only.

Review before installing if you need a strictly read-only updater. Run check with --no-baseline if you only want inspection, and use --execute, autoupdate --on, --force-overwrite, or --allow-major only when you are comfortable letting it modify installed skills from platform update sources.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill describes capabilities to read and write local files, invoke shell commands, and access the network, but it does not declare any explicit tool scope or permission boundaries. For an updater skill, these capabilities are especially sensitive because they can modify installed skills and fetch remote content; without clear scoping, the host may invoke it with broader privileges than users expect, increasing the chance of unintended file modification or remote-command abuse.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad enough to match ordinary discussion about skills or versions, which can cause the updater to run unexpectedly. In this skill's context, unintended invocation is more dangerous than usual because the skill can inspect local installations, contact remote endpoints, and potentially proceed toward update workflows that change files or execute platform CLI commands.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/selfcheck.py (reported line 112)May include surrounding context.

python
print("\n=== 7) 离线可用性(不联网也能检查) ===")
try:
    import subprocess
    r = subprocess.run([sys.executable, os.path.join(HERE, "skill_sync.py"),
                        "check", "--offline", "--no-baseline"],
                       capture_output=True, text=True, timeout=60,
                       cwd=os.path.dirname(SKILL_DIR))

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/selfcheck.py (reported line 125)May include surrounding context.

python
try:
    import subprocess
    exe = [sys.executable, os.path.join(HERE, "skill_sync.py")]
    r0 = subprocess.run(exe + ["autorun", "--help"], capture_output=True,
                        text=True, timeout=60)
    check("autorun 子命令已注册", r0.returncode == 0, r0.stderr[-120:])
    r = subprocess.run(exe + ["autorun"], capture_output=True, text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/selfcheck.py (reported line 128)May include surrounding context.

python
r0 = subprocess.run(exe + ["autorun", "--help"], capture_output=True,
                        text=True, timeout=60)
    check("autorun 子命令已注册", r0.returncode == 0, r0.stderr[-120:])
    r = subprocess.run(exe + ["autorun"], capture_output=True, text=True,
                       timeout=120, cwd=os.path.dirname(SKILL_DIR))
    check("autorun 退出码 0", r.returncode == 0, r.stderr[-160:])
    out = r.stdout or ""

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 · scripts/skill_sync.py (reported line 14)May include surrounding context.

python
设计铁律(勿改):
  1. 更新前必备份,失败必回滚。
  2. 检测到本地改动 → 不覆盖,先问(--force-overwrite 才强制)。
  3. 主版本变化 → 不自动执行(--allow-major 才允许)。
  4. 默认不联网改状态;每日自动检查默认关(opt-in)。
零第三方依赖(仅标准库),离线也能跑 check 的扫描部分。

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 · scripts/skill_sync.py (reported line 14)May include surrounding context.

python
设计铁律(勿改):
  1. 更新前必备份,失败必回滚。
  2. 检测到本地改动 → 不覆盖,先问(--force-overwrite 才强制)。
  3. 主版本变化 → 不自动执行(--allow-major 才允许)。
  4. 默认不联网改状态;每日自动检查默认关(opt-in)。
零第三方依赖(仅标准库),离线也能跑 check 的扫描部分。

Tainted flow: 'd' from open (line 171, file read) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/skill_sync.py (reported line 344)May include surrounding context.

python
continue
        s, d = os.path.join(slug_dir, entry), os.path.join(dest, entry)
        try:
            shutil.copytree(s, d) if os.path.isdir(s) else shutil.copy2(s, d)
        except Exception as e:
            print(f"  ⚠ 备份 {entry} 失败:{type(e).__name__}: {str(e)[:80]}")
    # 指针也写外部(写技能目录内会被 --force 一起删掉)

Tainted flow: 'd' from open (line 171, file read) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
74% confidence
Finding

Rollback restores files from a backup path read from last_backup.txt or user-supplied --backup, then recursively copies them into the skill directory without validating that the backup contents are safe. If an attacker can tamper with the backup pointer or backup directory, rollback can overwrite skill files with malicious content, effectively a local arbitrary file replacement vector.

Content

Scanner excerpt · scripts/skill_sync.py (reported line 369)May include surrounding context.

python
shutil.rmtree(p) if os.path.isdir(p) else os.remove(p)
    for entry in os.listdir(backup):
        s, d = os.path.join(backup, entry), os.path.join(slug_dir, entry)
        shutil.copytree(s, d) if os.path.isdir(s) else shutil.copy2(s, d)
    print(f"  ↩ 已回滚到 {backup}")
    return True

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
87% confidence
Finding

The script executes installer commands derived from remote version metadata (install_urls using cli:<platform>:<slug>) and local configuration without any authenticity verification, allowlist, or trust check. Even though shell=False reduces shell injection risk, this still enables supply-chain command execution: a compromised index service or tampered metadata can cause the tool to install and run attacker-controlled packages/CLI actions on the host.

Content

Scanner excerpt · scripts/skill_sync.py (reported line 449)May include surrounding context.

python
def run_install(item, timeout=180):
    """真实执行安装命令(仅当显式 --execute)。返回 (ok, 输出尾部)。"""
    try:
        r = subprocess.run(item["cmd"], cwd=item["cwd"] or None,
                           capture_output=True, text=True, timeout=timeout,
                           encoding="utf-8", errors="replace")
        out = ((r.stdout or "") + (r.stderr or "")).strip()

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

check mode is documented and advertised as read-only, but by default it writes baseline metadata into each scanned skill directory. This violates user expectations and can create unintended persistence or modify third-party skill contents, which is especially risky in a security-sensitive updater because it normalizes hidden state changes during an 'inspect only' operation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The inline documentation promises that check 'only inspects' and does not modify files, yet the implementation immediately below writes .cjg_sync metadata unless --no-baseline is used. In an updater skill, deceptive or inaccurate safety claims materially increase risk because users may run it in contexts where any write is forbidden or unexpected.

Content

No source excerpt is available for this finding.