T01 · Skill Instruction Hijacking
- Location
scripts/ralph-stop-hook.sh:113- Finding
Active Ralph State Unconditionally Overrides Agent Termination
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is not clearly malicious, but it installs persistent Claude Code hooks that can force the agent to continue, deny repeated tool calls, and run local diagnostics automatically.
Install only the specific hooks you need, preferably in a project-scoped configuration if available. Review the shell scripts first, avoid enabling Ralph for short or low-risk tasks, keep the cancel command handy, and replace or disable the npx-based TypeScript check unless it uses a pinned local dependency.
scripts/ralph-stop-hook.sh:113Active Ralph State Unconditionally Overrides Agent Termination
scripts/doubt-gate.sh:32Broad Language Matching Blocks Legitimate Agent Completion
scripts/tool-error-advisor.sh:28Failure Hooks Deny Tool Calls and Reflect Untrusted Error Text into Agent Context
scripts/post-edit-check.sh:33Automatic Post-Edit Hook Executes Unpinned npx Package Resolution
The skill instructs users to modify ~/.claude/settings.json, which is a sensitive agent configuration file controlling hook execution. Changes there can persistently alter agent behavior and enable automatic shell execution on future sessions, so guidance touching that path carries significant security risk if not tightly scoped and reviewed.
将需要的 hook 加入 ~/.claude/settings.json:
{
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
@pytest.fixture
def env(tmp_path):
e = os.environ.copy()
e["HOME"] = str(tmp_path)
sessions = tmp_path / ".openclaw" / "shared-context" / "sessions"
sessions.mkdir(parents=True)
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
@pytest.fixture
def env(tmp_path):
e = os.environ.copy()
e["HOME"] = str(tmp_path)
sessions = tmp_path / ".openclaw" / "shared-context" / "sessions"
sessions.mkdir(parents=True)
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
@pytest.fixture
def env(tmp_path):
e = os.environ.copy()
e["HOME"] = str(tmp_path)
sessions = tmp_path / ".openclaw" / "shared-context" / "sessions"
sessions.mkdir(parents=True)
The skill documents shell scripts that read environment variables, read and write files, and are installed as executable hooks, but it does not declare any explicit tool scope or permission boundaries. That omission increases the chance of over-broad execution in environments that rely on metadata for least-privilege review, making the effective capability set less visible to users and reviewers.
The trigger list includes broad phrases like 'persistent execution', 'speculative', 'hook scripts', and mixed-language short phrases that could match ordinary conversation. That can cause unintended invocation of a skill that installs or recommends shell-based hooks affecting stop behavior and tool execution, which is more dangerous than an accidental invocation of a read-only informational skill.
This markdown file presents all instructions and operational guidance exclusively in Chinese, with no opt-in, alternative language, or explanation that the skill is region-specific. That can violate a language/locale policy requiring user choice or documented justification rather than silently forcing one language.
This section recommends using PreToolUse updatedInput to directly rewrite tool commands, which changes what will execute without requiring the user or model to explicitly approve the modified action. In a hook system, that creates a command-integrity problem: a benign retry guard can silently transform intended operations into different package installs or shell commands with materially different security consequences.
The markdown explicitly describes direct command rewriting via updatedInput and gives an example that substitutes a failed build command with a package install plus alternate build command, without any warning or approval step. This is dangerous because the hook can cause execution of commands the operator did not request, including dependency installation or arbitrary shell actions, undermining trust boundaries and making abuse or accidental unsafe execution more likely.
The document extends a retry-mitigation hook into persistent auto-memory storage of errors and resolutions across sessions. Persisting failure details and derived fixes can unintentionally retain sensitive command output, paths, credentials, or project-specific context, creating a privacy and cross-session data exposure risk if retention, scoping, and sanitization are not tightly controlled.
The document’s instructional content and headings are written in Chinese, with no indication that users may choose another language or that the skill is intentionally limited to a Chinese-speaking context. This is a natural-language locale policy concern because it imposes a language requirement implicitly rather than through user opt-in or clear justification.
The entire skill description and user-facing block reason are written in Chinese, while the hook also matches both English and Chinese hedging terms. There is no indication that the skill is region-specific or that users can opt into a preferred language, which creates a language/locale policy concern.
The file’s instructional content is entirely in Chinese, including the title and all explanatory sections, with no indication that language selection is optional or that the skill is intended only for a Chinese-speaking or region-specific context. This creates a natural-language policy concern because it effectively imposes a locale/language choice on users without opt-in.
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
The hook invokes npx tsc without pinning a specific package/version, which can cause npx to resolve and execute an unexpected TypeScript compiler version from the network or local environment. In an automatic PostToolUse hook, this increases supply-chain risk because the command may run repeatedly and implicitly in developer environments without explicit review.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_doubt_gate(env, last_msg="", session_id="test-sess"):
env["NC_SESSION"] = session_id
inp = json.dumps({"last_assistant_message": last_msg})
result = subprocess.run(
["bash", str(SCRIPTS_DIR / "doubt-gate.sh")],
capture_output=True, text=True, env=env, input=inp, timeout=10,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
e.pop("NC_SESSION", None)
e["NC_SESSION"] = ""
inp = json.dumps({"last_assistant_message": "I think maybe this works"})
result = subprocess.run(
["bash", str(SCRIPTS_DIR / "doubt-gate.sh")],
capture_output=True, text=True, env=e, input=inp, timeout=10,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"tool_input": tool_input,
"hook_event_name": "PostToolUse",
})
result = subprocess.run(
["bash", str(SCRIPTS_DIR / "post-edit-check.sh")],
capture_output=True, text=True, input=inp, timeout=10,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd = ["bash", str(SCRIPTS_DIR / script_name)]
if args:
cmd.extend(args)
result = subprocess.run(
cmd, capture_output=True, text=True, env=env,
input=stdin_data, timeout=10,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run(script, env, stdin_data="", session_id="test-sess"):
env["NC_SESSION"] = session_id
result = subprocess.run(
["bash", str(SCRIPTS_DIR / script)],
capture_output=True, text=True, env=env, input=stdin_data, timeout=10,
)
The file presents core descriptive content and trigger phrases in both Chinese and English, including locale-specific phrases like "不要停" and Chinese operational guidance, but does not state whether users can choose their preferred language. This can create a language/locale policy concern if the skill implicitly assumes bilingual comprehension without opt-in.
The natural-language instructions and operational guidance are presented exclusively in Chinese, with no indication that language choice is optional or that the skill is intentionally region-specific. Under the stated policy, forcing a specific language without opt-in is a locale-policy issue.
The hook removes cancel.json via rm -f in both the active-cancel and expired-cancel paths. Although the behavior is commented for maintainers, there is no user-facing disclosure, confirmation, or visible runtime notice for this file deletion within the script.