T09 · Insecure Skill Coding Practices
- Location
scripts/script.sh:94- Finding
Workflow ID Path Traversal Enables Execution of Commands from External JSON Files
- Content
View full analysis
" && exit 1 local file="$STORE/$id.json" [ ! -f "$file" ] && echo "Workflow $id not found" && exit 1 WF_FILE="$file" python3 << 'PYEOF' import json, subprocess, os, datetime path = os.environ["WF_FILE"] with open(path) as f: d = json.load(f) print(f"\n🚀 Running workflow: [{d['id']}] {d['name']}") print(f" Steps: {len(d['steps'])}\n") d["status"] = "running" d["last_run"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") all_ok = True for step in d["steps"]: print(f" [{step['index']}/{len(d['steps'])}] {step['name']}...", end=" ", flush=True) step["status"] = "running" try: result = subprocess.run(step["command"], shell=True, capture_output=True, text=True, timeout=30) ``` The same unsafe path construction is also present in: - `scripts/script.sh:62-68` for `add-step` - `scripts/script.sh:130-134` for `status` - `scripts/script.sh:181-186` for `export` ### Technical Analysis The workflow identifier is inserted directly into the filesystem path: ```bash local file="$STORE/$id.json" ``` No allowlist validation, canonicalization, or containment check ensures that the resulting file remains under `$HOME/.bytesagain-workflows`. An identifier containing traversal components such as `../` can therefore resolve to a JSON file outside the workflow store. The `run` operation loads the selected file as JSON and passes every `steps[].command` value to: ```python subprocess.run(step["command"], shell=True, ...) ``` Shell command execution is an advertised feature of the Skill. The vulnerability arises because path traversal allows an external, potentially attacker-controlled JSON file to be treated as a trusted workflow definition. Th ...[truncated 2765 chars]- Remediation
View remediation
&2 exit 1 } } ``` Call this function from `add-step`, `run`, `status`, and `export`. 2. **Enforce canonical path containment.** Resolve both the store and candidate file to canonical paths and verify that the candidate's parent is exactly the workflow store. Do not rely only on substring or prefix comparisons. 3. **Reject traversal and separators explicitly.** Reject identifiers containing `/`, backslashes, `..`, control characters, or unexpected extensions. 4. **Protect against symlink traversal.** Reject symbolic links and verify that the final target is a regular file owned by the expected user. Where possible, open files using APIs that prevent symlink following. 5. **Apply restrictive storage permissions.** Create the store with mode `0700` and workflow files with mode `0600`, rather than relying on the caller's current `umask`. 6. **Validate the workflow schema before execution.** Confirm that all required fields have the expected types, impose limits on step counts and field lengths, and reject malformed definitions. 7. **Clarify the trust boundary for command execution.** Treat workflow files as executable code. If workflows can be imported or originate outside the protected store, require explicit user review or confirmation before executing their commands. 8. **Apply the fix consistently.** Centralize path construction and validation so `add-step`, `run`, `status`, and `export` cannot implement different security checks. ]]>
