T07 · Tool Hijacking and Spoofing
Warning
- Location
- scripts/install.py:237
- Finding
- Repository-Controlled Reminder Script Is Automatically Executed by a Persistent Claude Stop Hook## Vulnerability Details **File Location**: `scripts/install.py:237-243, 319-320, 404-407, 559-560` **Vulnerability Type**: Project-controlled hook executable / tool hijacking **Risk Level**: Medium ### Complete Code Snippets The installer copies executable reminder scripts into the project-controlled `.wiki/scripts/` directory: ```python pairs = ([(scripts_src / n, target / ".wiki" / "scripts" / n, "scripts/" + n) for n in RUNTIME_FILES] + [(refs_src / n, target / ".wiki" / "references" / n, "references/" + n) for n in REFERENCE_FILES]) for src, dst, label in pairs: if src.exists(): with_retry(lambda s=src, d=dst: shutil.copy2(str(s), str(d))) copied.append(label) else: missing.append(label) ``` It then constructs a hook command that directly executes the project-local script: ```python if project_level: rel = ".wiki/scripts/wiki_remind.py" if os.name == "nt" else ".wiki/scripts/wiki_remind.sh" return '%s "%s"' % (detect_python() if os.name == "nt" else "bash", rel) ``` The command is persisted as a Claude Code Stop hook: ```python settings.setdefault("hooks", {}).setdefault("Stop", []).append( {"hooks": [{"type": "command", "command": command}]}) write_text(settings_path, json.dumps(settings, indent=2, ensure_ascii=False) + "\n") ``` Project-level installation enables that behavior by default unless `--no-hook` is selected: ```python if args.no_hook or not spec["supports_hook"]: reason = "已用 --no-hook 指定" if args.no_hook else "平台无 hook 机制" print("[4/4] 跳过 hook 安装(%s)" % reason) else: settings_path = target / spec["user_dir"] / "settings.json" print("[4/4] " + merge_hook(settings_path, remind_command(True, target))) ``` ### Technical Analysis Project-level installation creates a persistent Claude Code hook whose executable payload remains inside the project tree. The ho ...[truncated 2755 chars]
- Remediation
- ## Remediation Suggestions 1. **Move executable hook helpers outside the repository.** Install the reminder script into a user-owned location such as `~/.claude/scripts/skill-evolution/` and configure both project-level and user-level hooks to invoke that protected copy. 2. **Keep repository content declarative.** Project files may contain reminder configuration or data, but automatically executed code should not be sourced from a collaborator-controlled working tree. 3. **If project-local execution is required, verify integrity before execution.** Use a trusted launcher outside the repository that: - Resolves the helper to an expected canonical path. - Rejects symbolic links and unexpected file types. - Computes and verifies a pinned cryptographic digest or signature. - Refuses execution when verification fails. 4. **Do not commit executable hook helpers by default.** Revise the recommendation to commit only non-executable `.wiki` data, or explicitly exclude `.wiki/scripts/` through version-control configuration. 5. **Require informed opt-in for project-local hooks.** Make `--no-hook` the default for project installation, clearly disclose that the configured hook will execute mutable project files, and require a dedicated flag to enable that behavior. 6. **Provide migration logic.** Existing installations should replace relative project-local hook commands with commands pointing to the protected user-owned runtime.
