T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/add-job.sh:36
- Finding
- Python Code Injection Through Job Fields and Database Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add-job.sh`, lines 36-103 **Vulnerability Type**: Python source-code injection through shell interpolation **Risk Level**: High ### Vulnerable Code ```bash python3 << PYEOF import json, datetime, sys db_path = "$DB" with open(db_path) as f: data = json.load(f) jobs = data.get("jobs", []) today = datetime.date.today().isoformat() # Find existing job existing = None for i, j in enumerate(jobs): if j.get("number") == "$NUMBER": existing = i break if existing is not None: job = jobs[existing] old_status = job.get("status", "") # Update only provided fields if "$CUSTOMER": job["customer"] = "$CUSTOMER" if "$ADDRESS": job["address"] = "$ADDRESS" if "$PM": job["pm"] = "$PM" if "$VALUE": job["value"] = float("$VALUE") if "$VALUE" else job.get("value", 0) if "$STATUS": job["status"] = "$STATUS" if "$PERMIT_STATUS": job["permit_status"] = "$PERMIT_STATUS" if "$PERMIT_NUMBER": job["permit_number"] = "$PERMIT_NUMBER" if "$NOTES": job["notes"] = "$NOTES" if "$TRADE": job["trade"] = "$TRADE" job["updated"] = today # Log status change new_status = job.get("status", "") if "$STATUS" and new_status != old_status: job.setdefault("history", []).append({ "date": today, "from": old_status, "to": new_status, "note": "$NOTES" or f"Status changed to {new_status}" }) else: job = { "number": "$NUMBER", "customer": "$CUSTOMER" or "Unknown", "address": "$ADDRESS" or "", "pm": "$PM" or "", "value": float("$VALUE") if "$VALUE" else 0, "status": "$STATUS" or "lead", "permit_status": "$PERMIT_STATUS" or "", "permit_number": "$PERMIT_NUMBER" or "", "trade": "$TRADE" or "", "notes": "$NOTES" or "", "created": today, "updated": today, "history": [{"date": today, " ...[truncated 1930 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Replace the expandable heredoc with a quoted heredoc such as `<<'PYEOF'`. - Pass job fields as command-line arguments, environment variables, stdin JSON, or another data channel rather than embedding them in Python source. - Prefer a structured JSON request read from stdin, then validate each field in Python. - Parse `value` as a finite, non-negative numeric value and reject malformed input. - Validate job status and permit status against explicit allowlists. - Pass the database path through `sys.argv` and resolve it with `pathlib.Path`. - Add regression tests containing double quotes, single quotes, backslashes, newlines, Unicode, and Python-like fragments in every accepted field. ]]>
