T09 · Insecure Skill Coding Practices
- Location
scripts/md2docx.sh:27- Finding
Arbitrary Command Execution Through Unsafe Shell Evaluation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/md2docx.sh, lines 27-39
Vulnerability Type: Shell command injection
Risk Level: HighVulnerable Code
bash # Build pandoc command PANDOC_CMD="pandoc \"$INPUT_MD\" -o \"$OUTPUT_DOCX\"" # Add reference template if exists TEMPLATE="$REFERENCES_DIR/template.docx" if [ -f "$TEMPLATE" ]; then PANDOC_CMD="$PANDOC_CMD --reference-doc=\"$TEMPLATE\"" fi # Add TOC PANDOC_CMD="$PANDOC_CMD --toc --toc-depth=3" # Execute echo "📄 Converting: $INPUT_MD → $OUTPUT_DOCX" eval $PANDOC_CMDTechnical Analysis
The script builds a shell command by interpolating the user-controlled
INPUT_MDandOUTPUT_DOCXarguments into a string, then executes that string witheval.Although literal quotation marks are added around the path values,
evalcauses the fully constructed string to be parsed by the shell again. An argument containing quotation marks and shell metacharacters can therefore terminate the intended quoted value and introduce an additional command.The input file existence check does not prevent exploitation through the optional output argument because
OUTPUT_DOCXis neither validated nor required to exist. Input-path injection may also be possible when an attacker can create a file whose crafted name passes the existence check.Attack Path
- An attacker causes the conversion script to be invoked with a normal Markdown input file and a maliciously constructed output path.
- The output path contains a quotation mark that terminates the intended argument, followed by shell syntax and an attacker-selected command.
- The script inserts that value into
PANDOC_CMD. - At line 39,
evalreparses the constructed text as shell code. - The injected command executes with the privileges and environment of the user or service running the Skill.
A representative malicious output-argument structure is:
text output.docx"; <attacker-selected-command>; #This structure is suffi ...[truncated 852 chars]
- Remediation
View remediation
Remediation Suggestions
Remove
evaland construct the Pandoc invocation as a Bash array. Arrays preserve argument boundaries without reparsing user-controlled values as shell syntax:bash PANDOC_CMD=(pandoc "$INPUT_MD" -o "$OUTPUT_DOCX") TEMPLATE="$REFERENCES_DIR/template.docx" if [ -f "$TEMPLATE" ]; then PANDOC_CMD+=(--reference-doc="$TEMPLATE") fi PANDOC_CMD+=(--toc --toc-depth=3) echo "📄 Converting: $INPUT_MD → $OUTPUT_DOCX" "${PANDOC_CMD[@]}"Additional hardening should include:
- Validate that input and output paths contain no control characters.
- Restrict output files to an explicitly approved workspace directory when the script is exposed through an automated service.
- Resolve and verify paths before execution to prevent writes outside the intended workspace.
- Run document conversion with least privilege and without unnecessary secrets in the process environment.
- Add regression tests using filenames containing spaces, quotation marks, semicolons, command substitutions, and newline characters to verify that they remain literal arguments.
- Where supported by the invoked utility, use an end-of-options marker or otherwise ensure path values cannot be interpreted as command-line options.
