T09 · Insecure Skill Coding Practices
- Location
scripts/design-loop.sh:45- Finding
Unrestricted Output Path Allows Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/design-loop.sh, lines 45-46, 62, and 70
Vulnerability Type: Unvalidated file path and destructive file overwrite
Risk Level: MediumVulnerable Code
bash --output) OUTPUT_FILE="$2" shift 2 ;;bash DESIGN_FILE="${OUTPUT_FILE:-$DATA_DIR/LOOP-DESIGN-${SKILL_NAME}-$(date +%Y%m%d).md}"bash cat > "$DESIGN_FILE" << EOFTechnical Analysis
The script accepts the
--outputargument and uses its value directly as the destination of a truncating shell redirection. It does not:- Restrict output to the intended data directory.
- Reject absolute paths or
..path traversal. - Detect symbolic links.
- Check whether the destination already exists.
- Require explicit authorization before overwriting an existing file.
Quoting
"$DESIGN_FILE"prevents shell word splitting and ordinary command injection, but it does not make the destination path safe. The>operator opens the selected file with truncation, replacing its contents before writing the generated Markdown.Consequently, a caller can select any file writable by the account executing the Skill. This behavior exceeds the expected function of creating a growth-loop report in the project data directory.
Attack Path
-
An attacker controls or influences the
--outputargument provided to the Skill. -
The Agent invokes the script with a sensitive writable destination, for example:
bash ./scripts/design-loop.sh \ --type viral \ --skill demo \ --output ../../some-writable-configuration-file -
The script assigns the supplied path to
OUTPUT_FILEwithout validation. -
DESIGN_FILEresolves directly to the attacker-selected path. -
cat > "$DESIGN_FILE"truncates the existing destination. -
The generated Markdown replaces the destination's previous contents.
A symbolic-link destination could similarly redirect the write to another file accessible to the executing accoun ...[truncated 718 chars]
- Remediation
View remediation
Remediation Suggestions
-
Confine generated files to a dedicated directory
- Resolve the canonical output directory.
- Treat user input as a filename rather than an unrestricted path.
- Verify that the resolved destination remains beneath the approved directory.
-
Reject dangerous path forms
- Reject absolute paths.
- Reject path components equal to
... - Apply a conservative filename allowlist, such as letters, digits, periods, underscores, and hyphens.
- Require the expected
.mdextension.
-
Prevent symbolic-link attacks
- Reject an existing destination if it is a symbolic link.
- Ensure parent path components are trusted and not attacker-controlled.
- Prefer secure file-opening mechanisms that support no-follow semantics where available.
-
Avoid implicit overwrite
- Refuse to replace an existing file by default.
- Add a separate
--forceoption if overwrite behavior is genuinely required. - Consider enabling shell no-clobber behavior with
set -o noclobberand handling failures explicitly.
-
Harden argument handling
- Confirm that options requiring values have a following argument before reading
$2. - Use
set -euo pipefailto catch unset arguments and pipeline failures.
- Confirm that options requiring values have a following argument before reading
A safer design would derive the output path from a validated basename:
bash case "$OUTPUT_FILE" in "" ) OUTPUT_NAME="LOOP-DESIGN-${SKILL_NAME}-$(date +%Y%m%d).md" ;; /*|*".."*|*/* ) echo "Error: --output must be a filename within the data directory" >&2 exit 1 ;; * ) OUTPUT_NAME="$OUTPUT_FILE" ;; esac if [[ ! "$OUTPUT_NAME" =~ ^[A-Za-z0-9._-]+\.md$ ]]; then echo "Error: Invalid output filename" >&2 exit 1 fi DESIGN_FILE="$DATA_DIR/$OUTPUT_NAME" if [[ -e "$DESIGN_FILE" || -L "$DESIGN_FILE" ]]; then echo "Error: Output already exists" >&2 exit 1 fi-
