Back to skill

Security audit

Workout Track

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent workout-logging purpose, but it handles database credentials and user-derived workout text through a shell command in a way that deserves review before installation.

Review this skill before installing. It appears intended to save workouts, not to steal data, but only use it with a dedicated low-privilege database account, protect the .env file, and avoid logging sensitive health notes until the shell-based insert path is replaced with a safer structured interface.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

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.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Session Persistence

Medium
Category
Rogue Agent
Content
## Setup

1. Create the database schema:
   ```bash
   psql -f skills/workout-track/schema.sql
   ```
Confidence
83% confidence
Finding
This skill is explicitly designed to persist workout-session data into a PostgreSQL database, which creates a real privacy and retention risk because personal health/fitness data is stored long-term. In context this appears intentional and functional rather than malicious, but the README does not mention retention limits, minimization, access controls, or user consent safeguards, so the persistence of sensitive lifestyle data is a genuine security/privacy concern.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares no explicit tool scope or allowed-tools despite instructing use of environment-backed shell execution. That increases the chance an agent can access sensitive local resources or invoke more powerful tools than intended, which is risky for a database-writing skill.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation text is broad enough to trigger on ordinary conversation about workouts, gym sessions, or exercise details. In this skill's context, accidental activation is more dangerous because it can lead to confirmation flows and eventual database writes for casual chat that was not intended to be persisted.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The markdown reveals the exact credential storage location without any sensitivity warning or access boundary. This materially lowers the bar for misuse by telling any agent or reader where high-value secrets live, especially in a skill already designed to invoke shell commands.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The skill explicitly tells the agent to source a local .env file containing database credentials. Exposing credential location and directing shell sourcing creates a path for secret disclosure, misuse of the database, or lateral abuse if the shell command is modified or logged.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The skill directs the agent to use arbitrary shell execution with user-derived JSON embedded into a bash command. Even with intended escaping, this pattern is dangerous because it combines shell execution, secret loading, and untrusted input, creating opportunities for command injection, credential exposure, or unintended system access.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest describes recording a workout into the life_db database, while the file docstring and SQL statements show inserts into `sport.sessions` and `sport.exercises`. This is a semantic mismatch in the described storage target, which could matter for user expectations and data placement.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
Line L05 states that all prompts and examples were translated to English, which suggests the skill may enforce a specific language. The policy allows locale constraints only when users are given a choice or the restriction is clearly justified, neither of which is present here.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The README presents the invocation example entirely in French, which implies a language-specific interaction pattern. There is no accompanying note that other languages are supported, optional, or that the skill is intentionally limited to French for a justified regional purpose.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The code documentation says the script inserts a strength training session into the `sport` schema, while the skill manifest says it inserts into `life_db`. This is an active documentation-versus-stated-intent contradiction rather than a mere omission.

Static analysis

No suspicious patterns detected.