T07 · Tool Hijacking and Spoofing
- Location
scripts/install.py:237- Finding
Repository-Controlled Reminder Script Is Automatically Executed by a Persistent Claude Stop Hook
- Content
View full analysis
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: MediumComplete 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-hookis 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
View remediation
Remediation Suggestions
-
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. -
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.
-
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.
-
Do not commit executable hook helpers by default. Revise the recommendation to commit only non-executable
.wikidata, or explicitly exclude.wiki/scripts/through version-control configuration. -
Require informed opt-in for project-local hooks. Make
--no-hookthe default for project installation, clearly disclose that the configured hook will execute mutable project files, and require a dedicated flag to enable that behavior. -
Provide migration logic. Existing installations should replace relative project-local hook commands with commands pointing to the protected user-owned runtime.
-
