T07 · Tool Hijacking and Spoofing
Error
- Location
- handler.sh:6
- Finding
- Execution of Untrusted Out-of-Package Scripts and Unsafe Command Delegation## Vulnerability Details **File Location**: `handler.sh:6-8, 17, 20, 32-34, 56-62`; related delegation instructions in `SKILL.md:26-29, 98-102` **Vulnerability Type**: Trust-boundary violation involving external local tools and unvalidated command delegation **Risk Level**: High ### Vulnerable Code ```bash WORKSPACE_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" SWITCH_SCRIPT="$WORKSPACE_DIR/scripts/switch-model.sh" STATUS_SCRIPT="$WORKSPACE_DIR/scripts/model-status.sh" LIST_SCRIPT="$WORKSPACE_DIR/scripts/list-models.sh" ``` ```bash chmod +x "$SWITCH_SCRIPT" "$STATUS_SCRIPT" "$LIST_SCRIPT" ``` ```bash if [ -n "$FILTER" ]; then "$LIST_SCRIPT" "$FILTER" else "$LIST_SCRIPT" fi ``` ```bash RESOLUTION="$($SWITCH_SCRIPT "$SELECTION")" STATUS="$(printf '%s' "$RESOLUTION" | node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(0, "utf8")); process.stdout.write(data.status || "");')" case "$STATUS" in ok) COMMAND="$(printf '%s' "$RESOLUTION" | node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(0, "utf8")); process.stdout.write(data.command || "");')" MODEL="$(printf '%s' "$RESOLUTION" | node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(0, "utf8")); process.stdout.write(data.model || "default");')" ``` The corresponding upper-layer instructions state: ```markdown - once the script returns a unique model, execute the returned command in the current session ``` ```markdown - `status: ok` - execute the returned `command` ``` ### Technical Analysis The handler derives three executable paths from a workspace directory outside the audited skill package. Those scripts are not included in the project, so their implementation and integrity cannot be established by reviewing this package. On every invocation, the handler also applies executable permissions to them and subsequently runs them with the skill's privileges. Although shell arguments are quoted and there is no direct shell interpola ...[truncated 2696 chars]
- Remediation
- ## Remediation Suggestions 1. Bundle `switch-model.sh`, `model-status.sh`, and `list-models.sh` within the reviewed skill package and resolve them from `SCRIPT_DIR`, rather than from a mutable workspace-level directory. 2. Remove runtime `chmod` calls. Set executable permissions during trusted packaging or installation and fail closed if permissions are incorrect. 3. If external scripts are unavoidable, verify canonical paths, file ownership, restrictive permissions, and cryptographic integrity before execution. Reject symlinks and files writable by untrusted users. 4. Do not return free-form executable commands from the resolver. Return structured data such as: ```json { "status": "ok", "operation": "switch_model", "provider": "openai", "model": "gpt-5.4" } ``` 5. Invoke a trusted session-model API directly with the validated provider and model identifiers. 6. If command-based integration is required, reconstruct the command in trusted code after strict validation. Permit only `/model default` or `/model <configured-provider/model>`, where the provider and model are confirmed against the active configuration. 7. Reject additional arguments, control characters, newlines, command separators, unsupported operations, and malformed JSON. 8. Update `SKILL.md` so the upper layer never executes a command merely because an external resolver labels its result `ok`. 9. Add tests covering replaced scripts, symlinks, writable script directories, malicious command fields, newline injection, malformed output, and unsupported model identifiers.
