T09 · Insecure Skill Coding Practices
- Location
src/address_classifier.py:447- Finding
Spreadsheet Formula Injection in CSV and TSV Exports
- Content
View full analysis
Vulnerability Details
File Location:
src/address_classifier.py, lines 447-461
Vulnerability Type: Spreadsheet formula injection caused by exporting untrusted fields without neutralization
Risk Level: MediumVulnerable Code:
python for result in results: line = f"{result.id}{delimiter}{result.original_address}{delimiter}" \ f"{result.classified_result}{delimiter}{result.category}{delimiter}" \ f"{result.province}{delimiter}{result.city}{delimiter}" \ f"{result.district}{delimiter}{result.remark}\n" f.write(line) def _write_csv(self, results: List[AddressResult], output_path: str): """Write CSV format.""" with open(output_path, 'w', encoding='utf-8-sig', newline='') as f: writer = csv.writer(f) writer.writerow([ 'id', 'original address', 'classification', 'category', 'province', 'city', 'district', 'complete', 'remark' ]) for result in results: writer.writerow([ result.id, result.original_address, result.classified_result, result.category, result.province, result.city, result.district, 'yes' if result.is_complete else 'no', result.remark ])Technical Analysis
The input record ID and address are attacker-controllable values. They are propagated into
AddressResultand written directly to spreadsheet-compatible CSV or delimiter-separated text output.The use of
csv.writerprovides syntactic CSV quoting, but it does not prevent spreadsheet applications from interpreting a cell beginning with=,+,-, or@as a formula. The TXT output has the same problem because fields are directly concatenated with a configurable delimiter.An attacker can therefore supply a value such as:
text =HYPERLINK("https://attacker.invalid/collect","Open record")When a generated file is open ...[truncated 1766 chars]
- Remediation
View remediation
Remediation Suggestions
Apply spreadsheet-safe neutralization to every string field before writing CSV or TSV output.
- Detect cells whose first non-whitespace character is
=,+,-, or@. - Prefix dangerous values with a single quote or another documented neutralization character appropriate for the intended spreadsheet consumers.
- Apply the protection consistently to IDs, original addresses, classification fields, location fields, and remarks.
- Preserve
csv.writerfor correct CSV escaping; formula neutralization is an additional requirement and does not replace CSV quoting. - Consider offering JSON as the preferred format when spreadsheet interoperability is unnecessary.
- Add regression tests for leading formula markers, leading whitespace before formula markers, embedded delimiters, quotes, tabs, and line breaks.
Example hardening helper:
python def spreadsheet_safe(value: object) -> str: text = "" if value is None else str(value) if text.lstrip().startswith(("=", "+", "-", "@")): return "'" + text return textApply this helper to every exported field before passing values to
csv.writeror constructing delimiter-separated output.- Detect cells whose first non-whitespace character is
