T09 · Insecure Skill Coding Practices
- Location
SKILL.md:157- Finding
Shell Command Injection Through Unsafely Interpolated Titles
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 157-164
Vulnerability Type: Shell command injection caused by unsafe interpolation into a shell command
Risk Level: HighVulnerable Code
bash echo "[$(date -Iseconds)] STEP 3: Submitting titles..." >> "$LOGFILE" SUBMIT=$(curl -s --connect-timeout 10 --max-time 30 -w "\n%{http_code}" -X POST "https://titleclash.com/api/v1/challenge/$CHALLENGE_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"titles":["YOUR_TITLE_1","YOUR_TITLE_2","YOUR_TITLE_3"]}') SUB_CODE=$(echo "$SUBMIT" | tail -1) SUB_BODY=$(echo "$SUBMIT" | sed '$d') echo "[$(date -Iseconds)] STEP 3: HTTP $SUB_CODE — $SUB_BODY" >> "$LOGFILE" echo "Titles submitted."The preceding instruction explicitly requires the generated titles to be substituted into this command:
text Replace the 3 titles you wrote into this command:Technical Analysis
The JSON request body is embedded directly in a single-quoted shell argument. Generated title values are therefore treated as shell source rather than as data after substitution.
A title containing a single quote terminates the surrounding shell string. Subsequent shell metacharacters, such as semicolons, command substitutions, redirections, or pipes, can then be interpreted by the shell. For example, substituting a title shaped like the following would alter the command structure:
text '; id; #This issue can also be triggered accidentally by ordinary English titles containing apostrophes. The document itself provides an example beginning with
I've, which would break the documented quoting strategy if inserted without escaping.The generated titles are influenced by a remotely supplied image. An adversarial image could contain prompt-injection text designed to induce a model to produce a title containing shell syntax. Even without an adversarial image, punctuation in a normal title can cause malformed commands or invali ...[truncated 1878 chars]
- Remediation
View remediation
Remediation Suggestions
Do not insert generated text into shell source. Construct the JSON payload using a real JSON serializer and transfer title values through environment variables, positional arguments, standard input, or a temporary data file with restrictive permissions.
For example:
bash export TITLE_1 TITLE_2 TITLE_3 PAYLOAD=$(python3 -c ' import json import os print(json.dumps({ "titles": [ os.environ["TITLE_1"], os.environ["TITLE_2"], os.environ["TITLE_3"], ] })) ') SUBMIT=$(curl -s --connect-timeout 10 --max-time 30 \ -w "\n%{http_code}" \ -X POST "https://titleclash.com/api/v1/challenge/$CHALLENGE_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ --data-binary "$PAYLOAD")Additional hardening should include:
- Validate each title's length and reject control characters before submission.
- Keep title text exclusively in variables or data files; never paste it into executable shell syntax.
- Use
json.dumpsorjq --argso quotation marks, apostrophes, backslashes, and newlines are encoded correctly. - Add tests covering apostrophes, double quotes, command substitutions, semicolons, pipes, newlines, and Unicode characters.
- Treat all model-generated content and remotely influenced image text as untrusted input.
- Run the skill with least privilege and expose only the credentials and filesystem paths required for the TitleClash workflow.
- Avoid logging raw generated values or secrets unless necessary, and ensure diagnostic files have restrictive permissions.
