T09 · Insecure Skill Coding Practices
- Location
scripts/quebec_data.py:198- Finding
CSV Formula Injection in Dataset Export
- Content
View full analysis
Vulnerability Details
File Location:
scripts/quebec_data.py, lines 198–203
Vulnerability Type: CSV formula injection caused by insufficient sanitization of untrusted remote data
Risk Level: MediumVulnerable Code
python if options.get("csv"): keys = list(records[0].keys()) print(",".join(keys)) for row in records: vals = [str(row.get(k, "")).replace(",", ";").replace("\n", " ") for k in keys] print(",".join(vals))Technical Analysis
Dataset field names and values originate from the external CKAN service and are therefore untrusted. The CSV export logic removes commas and newline characters but does not neutralize cells beginning with spreadsheet formula indicators such as
=,+,-, or@.If an attacker can insert data into a listed dataset, or compromise its upstream source, a generated CSV can contain formula expressions. When a user opens that file in spreadsheet software, the application may interpret the values as formulas rather than plain text. The implementation also constructs CSV output manually instead of using a standards-compliant CSV writer, so quoting and escaping behavior is incomplete.
Attack Path
- An attacker gains the ability to add or modify a value in a CKAN dataset consumed by the skill.
- The attacker supplies a formula-like value, such as one beginning with
=,+,-, or@. - A user runs a command such as:
bash python3 scripts/quebec_data.py fetch DATASET_ID --csv > output.csv - The export routine writes the attacker-controlled value without formula neutralization.
- The user opens
output.csvin spreadsheet software. - If that software evaluates CSV cells as formulas, the injected expression executes within the spreadsheet application's security context.
Impact Assessment
Exploitation does not grant privileges inside the Python process itself. Impact occurs when the exporte ...[truncated 452 chars]
- Remediation
View remediation
Remediation Suggestions
- Use Python's standard
csvmodule rather than constructing rows with",".join(...). This provides standards-compliant quoting and escaping. - Treat both field names and field values as untrusted.
- Before writing each cell, detect formula-leading content after any relevant leading whitespace. Neutralize cells beginning with
=,+,-, or@, for example by prefixing a single quote when compatibility with the target spreadsheet allows it. - Apply the same protection consistently to the header row.
- Document that CSV output contains untrusted public dataset content and should be imported as text when possible.
- Add tests covering formula indicators, commas, quotes, carriage returns, line feeds, Unicode content, and leading whitespace.
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) 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)- Use Python's standard
