T09 · Insecure Skill Coding Practices
- Location
scripts/log_store.py:194- Finding
CSV Formula Injection in Nutrition Log Export
- Content
View full analysis
Vulnerability Details
File Location:
scripts/log_store.py, lines 194–221
Vulnerability Type: CSV formula injection
Risk Level: MediumVulnerable Code
python def append_csv(log_dir, entries): ensure_log_dir(log_dir) with csv_path(log_dir).open("w", encoding="utf-8-sig", newline="") as handle: writer = csv.DictWriter(handle, fieldnames=CSV_FIELDS) writer.writeheader() for entry in entries: for item in entry.get("items", []): nutrition = item.get("nutrition") or {} row = { "date": entry.get("date"), "time": entry.get("time"), "timezone": entry.get("timezone"), "meal": entry.get("meal"), "food": item.get("food"), "amount_raw": item.get("amount_raw"), "amount_g": item.get("amount_g"), "source": item.get("source"), "confidence": item.get("confidence"), "note": item.get("note"), "raw_message": entry.get("raw_message"), "entry_id": entry.get("entry_id"), } for field in CSV_NUTRIENT_FIELDS: row[field] = nutrition.get(field) writer.writerow(row)Technical Analysis
The application writes attacker-influenced text fields directly to
food_log.csvwithout neutralizing spreadsheet formula prefixes. Relevant fields includefood,amount_raw,note, andraw_message.CSV quoting performed by
csv.DictWriterprotects the CSV structure but does not prevent spreadsheet applications from interpreting cell contents as formulas. A value beginning with=,+,-, or@, including one preceded by whitespace, may therefore be evaluated when the generated file is opened in Excel or compatible spreadsheet software.For example, a crafted food name or raw messag ...[truncated 1462 chars]
- Remediation
View remediation
Remediation Suggestions
Introduce a dedicated CSV-cell sanitization function for every user-influenced textual field:
- Convert the value to text when appropriate.
- Inspect the first non-whitespace character.
- If it is
=,+,-, or@, prefix the value with a single quote or another spreadsheet-safe neutralization marker. - Preserve numeric fields as numeric values rather than applying text sanitization indiscriminately.
- Apply sanitization immediately before
writer.writerow(row)so all CSV export paths receive consistent protection. - Add regression tests covering formula prefixes, leading whitespace, tabs, carriage returns, and newlines.
- Document that JSONL remains the canonical data format and that CSV output is intended for spreadsheet consumption.
Example hardening pattern:
python DANGEROUS_CSV_PREFIXES = ("=", "+", "-", "@") def sanitize_csv_text(value): if value is None: return None text = str(value) if text.lstrip().startswith(DANGEROUS_CSV_PREFIXES): return "'" + text return textApply this function to fields such as
food,amount_raw,note,raw_message,meal, and other text values that may be derived from untrusted input.
