T09 · Insecure Skill Coding Practices
- Location
scripts/build_article_inventory.py:174- Finding
Spreadsheet Formula Injection in Generated CSV Inventory
- Content
View full analysis
None: fieldnames = [ "id", "relative_path", "title", "source_type", "processing_status", "extension", "has_frontmatter", "frontmatter_keys", "publish_status", "chars", "lines", "h1_count", "preview", ] with path.open("w", encoding="utf-8", newline="") as handle: writer = csv.DictWriter(handle, fieldnames=fieldnames) writer.writeheader() writer.writerows(records) ``` ### Technical Analysis Several record fields are derived from files in the scanned source directory, including filenames, relative paths, document titles, frontmatter keys and values, and document previews. These values are passed directly to `csv.DictWriter` without neutralizing spreadsheet formula prefixes. CSV quoting performed by Python protects the structural integrity of the CSV file, but it does not stop spreadsheet software from interpreting cells beginning with `=`, `+`, `-`, or `@` as formulas. A malicious source document can therefore place a formula in its t ...[truncated 1944 chars]- Remediation
View remediation
object: if not isinstance(value, str): return value stripped = value.lstrip() if stripped.startswith(DANGEROUS_CSV_PREFIXES): return "'" + value return value ``` Sanitize all fields rather than only titles or previews: ```python safe_records = [ {key: sanitize_csv_cell(value) for key, value in record.items()} for record in records ] writer.writerows(safe_records) ``` Additional hardening measures should include: 1. Treat filenames, paths, frontmatter, titles, and document bodies as untrusted input. 2. Account for leading spaces, tabs, carriage returns, and line feeds before formula prefixes. 3. Document that CSV output is intended to contain text rather than executable spreadsheet formulas. 4. Add regression tests covering values beginning with `=`, `+`, `-`, and `@`. 5. Test malicious values in filenames, titles, frontmatter values, frontmatter keys, publication status, and preview text. 6. Preserve the unsanitized values in JSONL only if consumers are clearly informed that the content is untrusted. ]]>
