T09 · Insecure Skill Coding Practices
- Location
scripts/fetch-stats.sh:26- Finding
Python Code Injection Through an Untrusted Skill Slug
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch-stats.sh, lines 26-27
Vulnerability Type: Python source-code injection
Risk Level: HighVulnerable Code
bash for SLUG in $SLUGS; do NOTE=$(cat "$CONFIG_FILE" | python3 -c "import sys,json; skills=json.load(sys.stdin)['skills']; print(next((s['note'] for s in skills if s['slug']=='$SLUG'),''))" 2>/dev/null)Technical Analysis
The script reads each
slugfrom~/.clawhub/tracked-skills.jsonand interpolates it directly into source code passed topython3 -c.Although the shell quotes
SLUGin most command arguments, that does not make the value safe for insertion into Python source. A slug containing Python quote characters and expressions can terminate or alter the intended string literal. The injected expression is then evaluated by Python under the privileges of the user running the Skill.For example, an attacker-controlled slug can alter the generator condition from a simple equality comparison into an expression that invokes
__import__("os").system(...). Payloads can be constructed without spaces, avoiding the script's word-splitting behavior.The configuration file is local rather than directly remote, so exploitation requires the attacker, another compromised process, or an unsafe configuration-generation workflow to modify
~/.clawhub/tracked-skills.json.Attack Path
- An attacker obtains the ability to create or modify an entry in
~/.clawhub/tracked-skills.json. - The attacker places Python syntax in the entry's
slugfield so that it escapes the intended Python string literal. - The user invokes
scripts/fetch-stats.sh, directly or through the Skill. - The shell substitutes the malicious slug into the
python3 -csource string. - Python parses the resulting text as executable source code.
- The injected expression executes with the operating-system privileges and environment of the user running the S ...[truncated 494 chars]
- An attacker obtains the ability to create or modify an entry in
- Remediation
View remediation
Remediation Suggestions
Never interpolate configuration values into Python source code. Pass the slug as a positional argument and treat it strictly as data:
bash NOTE=$( python3 -c ' import json import sys target = sys.argv[1] skills = json.load(sys.stdin)["skills"] print(next((s.get("note", "") for s in skills if s.get("slug") == target), "")) ' "$SLUG" < "$CONFIG_FILE" )Additional hardening should include:
- Parse the JSON configuration once rather than invoking Python separately for every entry.
- Iterate over records using a null-delimited or structured-data mechanism instead of
for SLUG in $SLUGS. - Validate slugs against ClawHub's documented slug syntax, preferably with a strict allowlist such as lowercase letters, digits, and hyphens.
- Reject malformed JSON, missing keys, non-string slugs, and unexpected configuration structures with explicit errors.
- Avoid suppressing all parser errors with
2>/dev/null, because doing so obscures security-relevant failures.
