T09 · Insecure Skill Coding Practices
- Location
resources/graph-stop-evaluator.sh:9- Finding
Workspace-Controlled Python Evaluator Is Automatically Executed by a Stop Hook
- Content
View full analysis
Vulnerability Details
File Location:
resources/graph-stop-evaluator.sh, lines 9–26
Vulnerability Type: Execution of untrusted workspace code
Risk Level: HighVulnerable Code
bash ES6KR_ROOT="${CLAUDE_PROJECT_ROOT:-$(pwd)}" AGENTS_ROOT="${ES6KR_ROOT}/.agents" if [[ ! -d "${AGENTS_ROOT}" ]]; then # Fallback if invoked outside es6kr root AGENTS_ROOT="${HOME}/.agents" fi RUNNER="${AGENTS_ROOT}/graph/scripts/run_stop_evaluator.py" if [[ ! -f "${RUNNER}" ]]; then exit 0 fi # Execute evaluator in auto-drain mode (sub-100ms) PYTHONPATH="${AGENTS_ROOT}" python3 "${RUNNER}" \ --workspace "${ES6KR_ROOT}" \ --auto-drain \ --format summary 2>&1 || trueTechnical Analysis
The wrapper derives
AGENTS_ROOTfrom the active project root whenever the workspace contains an.agentsdirectory. It then executes.agents/graph/scripts/run_stop_evaluator.pydirectly and places the same workspace-controlled directory inPYTHONPATH.Consequently, repository content is treated as trusted native code solely because the repository is the current workspace. An untrusted repository or lower-trust workspace contributor can supply the evaluator script. The attacker may also place malicious Python modules under
.agentsthat are imported by an otherwise legitimate evaluator due to thePYTHONPATHassignment.The script only verifies that the target is a regular path accepted by
-f. It does not verify that the evaluator belongs to a trusted installation, resolve and constrain symlinks, validate ownership or permissions, or check a pinned hash or signature. The|| truesuffix also suppresses a nonzero result from the payload, reducing the visibility of failed or partially completed malicious activity.Attack Path
- An attacker prepares or modifies a repository containing:
.agents/graph/scripts/run_stop_evaluator.py, or- a malicious Python module under
.agentsthat the evaluator imports.
- A victim opens or works ...[truncated 1415 chars]
- An attacker prepares or modifies a repository containing:
- Remediation
View remediation
Remediation Suggestions
- Resolve
run_stop_evaluator.pyexclusively from a trusted installation directory outside the active workspace. Do not prefer${CLAUDE_PROJECT_ROOT}/.agentsfor executable hook code. - Remove the workspace-controlled
PYTHONPATHassignment. Use an isolated, trusted module path or a packaged evaluator with pinned dependencies. - If workspace-local evaluators are an intentional extension mechanism, require explicit user approval before first execution and bind that approval to the repository identity and evaluator digest.
- Canonicalize the evaluator path with a mechanism such as
realpath, reject symlinks, and ensure the resolved path remains under an approved directory. - Validate ownership and permissions so lower-trust local users or repository content cannot replace the approved evaluator.
- Verify the evaluator against a pinned cryptographic hash or trusted signature before execution.
- Avoid silently suppressing all failures with
|| true. Record a clear, sanitized failure event so unexpected evaluator behavior remains visible without exposing sensitive output. - Run the evaluator with reduced privileges and a minimal environment where practical, restricting filesystem and network access to what Stop-state evaluation actually requires.
- Resolve
