T09 · Insecure Skill Coding Practices
- Location
scripts/generate_project_docs.sh:14- Finding
Unconditional Overwrite of Existing Project Files
- Content
View full analysis
Vulnerability Details
File Location:
scripts/bootstrap_tree.sh:18-662,scripts/generate_gemini_md.sh:4-37, andscripts/generate_project_docs.sh:14-26
Vulnerability Type: Uncontrolled file overwrite and data loss
Risk Level: MediumVulnerable Code
scripts/bootstrap_tree.shrepeatedly overwrites generated Skill files:bash cat > "$root/skills/nextjs/SKILL.md" <<'EOF' --- name: nextjs description: Use this skill for Next.js App Router work including pages, layouts, route handlers, server actions, metadata, loading/error states, and server/client component boundaries. ---The same unconditional redirection pattern is used for every generated
skills/*/SKILL.mdfile through line 662.scripts/generate_gemini_md.shoverwrites the caller-selected output file:bash out="${1:-GEMINI.md}" cat > "$out" <<'EOF' # Source of truth 1. docs/requirements.md 2. docs/scope.md 3. docs/architecture.md 4. docs/conventions.md 5. docs/decisions/*.md 6. docs/notes/brainstorming.md is reference only # Stack policy - Frontend: Next.js App Router - UI: Tailwind + shadcn/ui - DB: Neon PostgreSQL - ORM: Prisma - Auth: Clerk - Email: Resend - Payments: Stripe - Storage: Cloudflare R2 - Analytics: PostHog - Error Monitoring: Sentry - Deploy: Vercel - Backend: FastAPI only for Python-required workloads # Backend boundary - Default backend logic lives in Next.js route handlers or server actions - FastAPI is only for AI, batch, heavy processing, or Python-specific integrations # Never do - Do not duplicate Clerk auth state into Prisma as a full auth system - Do not treat Stripe success redirect as source of truth; use webhook state - Do not store uploaded files in PostgreSQL - Do not add FastAPI endpoints for simple CRUD unless explicitly required EOFscripts/generate_project_docs.shoverwritesGEMINI.mdand six existing documen ...[truncated 5198 chars]- Remediation
View remediation
Remediation Suggestions
-
Refuse to replace existing files by default:
bash if [[ -e "$out" ]]; then printf 'Refusing to overwrite existing file: %s\n' "$out" >&2 exit 1 fi -
Add an explicit
--forceoption for intentional replacement. Clearly document that it is destructive. -
Generate content into a securely created temporary file in the destination directory, validate successful generation, and atomically rename it:
bash destination="$root/docs/requirements.md" tmp="$(mktemp "$root/docs/.requirements.md.XXXXXX")" trap 'rm -f "$tmp"' EXIT gemini -p "$prompt" > "$tmp" [[ -s "$tmp" ]] || { echo "Generated document is empty" >&2 exit 1 } mv -- "$tmp" "$destination" trap - EXIT -
Check every external command's output before replacing trusted files. This prevents an authentication failure, quota error, or empty response from destroying the previous document.
-
Reject symbolic-link destinations unless following them is explicitly intended:
bash if [[ -L "$destination" ]]; then echo "Refusing to overwrite symbolic link: $destination" >&2 exit 1 fi -
Canonicalize and validate the project root before writing. Ensure all generated destinations remain beneath that root.
-
Offer
--backup,--dry-run, and interactive confirmation modes for existing projects. -
Prefer scaffold-only semantics: create absent files and report conflicts so the user can merge generated content manually.
-
