T09 · Insecure Skill Coding Practices
- Location
scripts/montreal_data.py:112- Finding
CSV Formula Injection in Exported Dataset Records
- Content
View full analysis
Vulnerability Details
File Location:
scripts/montreal_data.py, lines 112–116
Vulnerability Type: CSV formula injection and improper CSV encoding
Risk Level: Mediumpython if options.get("csv"): keys = list(records[0].keys()) print(",".join(keys)) for row in records: print(",".join([str(row.get(k, "")).replace(",", ";") for k in keys]))Technical Analysis
The CSV export incorporates remotely retrieved CKAN field names and record values without neutralizing spreadsheet formula prefixes. Cells beginning with
=,+,-, or@may be interpreted as formulas when the resulting file is opened in formula-capable spreadsheet software.Replacing commas with semicolons is not a safe CSV-encoding mechanism. It does not correctly handle quotation marks, carriage returns, line feeds, or other characters that can alter the output structure. Headers are also emitted without any encoding or formula neutralization.
Exploitation requires attacker-controlled content to enter a dataset returned by the remote CKAN service, followed by a user exporting and opening that data in spreadsheet software that evaluates formulas. The Python script itself does not execute the formulas.
Attack Path
- An attacker obtains the ability to add or modify a field name or record value in a dataset accessible through the Montreal CKAN service.
- The attacker supplies a value whose first significant character is a spreadsheet formula prefix, such as
=,+,-, or@. - A user runs a command such as
python3 scripts/montreal_data.py fetch DATASET_ID --csv > output.csv. - The Skill writes the attacker-controlled value into
output.csvwithout formula neutralization. - The user opens the exported file in spreadsheet software.
- If formula evaluation is enabled and supported by that software, the attacker-controlled cell is evaluated.
Impact Assessment
The vulnerability does no ...[truncated 648 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace manual string concatenation with Python's standard
csv.writer, using an explicit newline and encoding configuration. - Treat both headers and record values as untrusted data.
- Before writing each cell, detect whether its first non-whitespace character is
=,+,-, or@. Neutralize such cells according to the intended consumer, commonly by prefixing a single quote. - Preserve standards-compliant CSV quoting instead of replacing commas, so embedded commas, quotes, carriage returns, and line feeds cannot alter the record structure.
- Document that exported data originates from a remote source and should not be trusted when opened in formula-capable applications.
- Add tests covering formula prefixes, leading whitespace before formulas, embedded quotes, commas, and multiline values.
Example hardening approach:
python import csv def safe_csv_cell(value): text = str(value if value is not None else "") if text.lstrip().startswith(("=", "+", "-", "@")): return "'" + text return text writer = csv.writer(sys.stdout, lineterminator="\n") writer.writerow([safe_csv_cell(key) for key in keys]) for row in records: writer.writerow([safe_csv_cell(row.get(key, "")) for key in keys])- Replace manual string concatenation with Python's standard
