T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/excel_toolkit.py:45
- Finding
- Spreadsheet Formula Injection in Generated Excel Workbooks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/excel_toolkit.py`, lines 45–47 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: High ### Vulnerable Code ```python # Write headers and data ws.append(list(df.columns)) for row in df.itertuples(index=False): ws.append(list(row)) ``` The affected function is reachable through conversion and report-generation operations: ```python df = read_data(src) if dst.endswith('.csv'): df.to_csv(dst, index=False, encoding='utf-8-sig') elif dst.endswith('.xlsx'): write_report(df, dst) ``` ### Technical Analysis The `write_report` function copies column names and cell values from a pandas `DataFrame` directly into an XLSX workbook. It does not distinguish ordinary text from values beginning with formula-control characters such as: - `=` - `+` - `-` - `@` When attacker-controlled CSV or JSON data contains such a value, `openpyxl` can store it as an active spreadsheet formula rather than inert text. The generated workbook therefore crosses a trust boundary: content from an untrusted source becomes executable spreadsheet syntax. Depending on the spreadsheet application and its security configuration, malicious formulas can: - Cause outbound requests that disclose data through attacker-controlled URLs. - Display deceptive values or links. - Reference external workbooks or resources. - Abuse application-specific formula or external-data features. - Trigger legacy command-execution behavior in vulnerable or permissively configured spreadsheet environments. ### Attack Path 1. An attacker creates a CSV or JSON document containing a malicious cell, such as a value beginning with `=`. 2. A user runs the toolkit's `convert` or `report` command on the attacker-controlled document. 3. `read_data` imports the malicious value into a `DataFrame`. 4. `write_report` passes the value directly to `ws.append` without neutralization. 5. The toolkit saves the value as an active formula in the ...[truncated 1026 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Sanitize all externally sourced headers and string values before writing them to a spreadsheet. 2. Treat strings beginning with `=`, `+`, `-`, or `@` as potentially dangerous. 3. Prefix dangerous values with an apostrophe or explicitly force the destination cell to use a string data type. 4. Apply protection to both data cells and column headers. 5. Make formula support opt-in rather than enabled implicitly for imported data. 6. Document whether formula preservation is expected for XLSX-to-XLSX operations. Example defensive helper: ```python def neutralize_spreadsheet_formula(value): if isinstance(value, str) and value.startswith(("=", "+", "-", "@")): return "'" + value return value ``` Apply it before writing: ```python ws.append([neutralize_spreadsheet_formula(v) for v in df.columns]) for row in df.itertuples(index=False): ws.append([neutralize_spreadsheet_formula(v) for v in row]) ``` Add regression tests covering malicious values in both headers and cells, and verify that reopening the resulting workbook returns literal text rather than formula cells. ]]>
