T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:58
- Finding
- Shell Command Injection Through User-Controlled JSON Payload## Vulnerability Details **File Location**: `SKILL.md:58-65` **Vulnerability Type**: Shell command injection and excessive credential exposure **Risk Level**: High ### Vulnerable Code ```text Only after confirmation, use the `exec` tool: { "tool": "exec", "command": "bash -c 'set -a; source ~/.openclaw/services/life-db/.env; uv run --project ~/.openclaw {baseDir}/scripts/insert_workout.py <json>'" } Replace `<json>` with the minified JSON payload (no newlines, properly shell-escaped). ``` ### Technical Analysis The Skill instructs the Agent to place a JSON document derived from user-controlled workout data directly inside a `bash -c` command. Correct shell escaping is delegated to the Agent rather than enforced by an argument-safe execution interface. Fields such as exercise names and notes may contain quotes, command substitutions, shell metacharacters, or other syntax that can escape the intended argument if serialization is incomplete. The command loads credentials before processing the payload: ```bash set -a source ~/.openclaw/services/life-db/.env ``` `source` executes the `.env` file as shell code rather than parsing it strictly as data. `set -a` then exports every variable assigned by that file to subsequently launched processes. This is broader than necessary because the insertion script only requires `DATABASE_URL` or the PostgreSQL connection variables. The Python implementation uses parameterized SQL, so direct SQL injection was not identified. The vulnerability exists at the shell-command construction boundary before Python parses the JSON. ### Attack Path 1. An attacker supplies workout information containing shell syntax in a free-text field such as `notes` or `exercise_name`. 2. The Agent parses that content and includes it in the minified JSON payload. 3. The Agent interpolates the payload into the documented `bash -c` command. 4. If quoting or escaping is incomplete ...[truncated 1309 chars]
- Remediation
- ## Remediation Suggestions 1. Remove `bash -c` and invoke the Python script through an execution API that accepts an argument array without shell interpretation. 2. Prefer passing the JSON document through standard input rather than embedding it in a command string. 3. Update `insert_workout.py` to read and decode JSON from standard input, with a documented size limit. 4. Load the environment file using a strict dotenv parser instead of `source`, ensuring that its contents cannot execute shell code. 5. Allowlist only `DATABASE_URL` or `PGHOST`, `PGPORT`, `PGDATABASE`, `PGUSER`, and `PGPASSWORD`; do not export unrelated variables. 6. Protect the credential file with restrictive filesystem permissions, such as mode `0600`. 7. Configure a dedicated database role restricted to the required schema and operations. It should not own the database, create roles, create extensions, or access unrelated schemas. 8. Add explicit application-level validation and length limits for dates, numeric fields, exercise names, notes, and the number of exercises. 9. If a shell cannot be eliminated, generate the argument with a proven escaping routine and pass it positionally rather than through textual interpolation. Shell removal remains the preferred fix.
