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

Content
View full analysis

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
View 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
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.

Content

Scanner excerpt · README.md (reported line 17)May include surrounding context.

Setup

  1. Create the database schema:
    bash
    psql -f skills/workout-track/schema.sql
    

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.