T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/excel_import.py:818
- Finding
- Untrusted spreadsheet values can be written as executable formulas<![CDATA[ ## Vulnerability Details **File Location**: `scripts/excel_import.py:818-829` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: High ### Complete Code Snippet ```python for col, value in write_plan: target_cell = self.target_ws.cell(row=target_row, column=col) if is_cell_merged(target_cell, self.target_ws.merged_cells.ranges): continue cached_styles = { "number_format": target_cell.number_format, "font": copy.copy(target_cell.font) if target_cell.font else None, "fill": copy.copy(target_cell.fill) if target_cell.fill else None, "border": copy.copy(target_cell.border) if target_cell.border else None, "alignment": copy.copy(target_cell.alignment) if target_cell.alignment else None, } target_cell.value = value ``` The values reaching this sink are read directly from source CSV and XLSX files: ```python row_data[name] = row[col_idx].strip() if row[col_idx] else None ``` ```python cell = ws.cell(row=row, column=col) row_data[name] = cell.value if cell is not None else None ``` ### Technical Analysis The importer transfers attacker-controlled spreadsheet or CSV values into output workbook cells without checking whether a string is a formula. In particular, OpenPyXL treats strings beginning with `=` as formulas when the workbook is saved. An attacker can place a formula, external-reference formula, hyperlink formula, or DDE-style expression in a mapped source field. The importer preserves that expression as active workbook content instead of treating it as literal text. The vulnerability crosses a trust boundary: a source data file is treated as passive input, but its content can become executable spreadsheet syntax in a generated artifact. ### Attack Path 1. An attacker creates a CSV or XLSX source file containing a mapped value such as an external-reference or DDE-style formula beginning with `=`. 2. A user imports the file using the Skill. 3. `_load_csv()` ...[truncated 1105 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat imported strings as literal text by default. 2. Before assigning a source value, detect dangerous formula prefixes, especially `=`, and account for leading whitespace, tabs, and control characters. 3. Prefix untrusted formula-like strings with an apostrophe or explicitly store them as string cells. 4. Permit formulas only through an explicit configuration option that is disabled by default and limited to trusted source files. 5. Apply the same policy to CSV, XLSX, XLS, mapping defaults, headers, and any future import formats. 6. Add tests covering direct formulas, leading-whitespace formulas, external references, hyperlinks, and DDE-style payloads. 7. Warn users when formula-like input is rejected or neutralized. Example defensive logic: ```python def neutralize_formula(value): if not isinstance(value, str): return value normalized = value.lstrip("\t\r\n ") if normalized.startswith("="): return "'" + value return value ``` For stronger protection, reject formula-like values rather than modifying them when the affected field is expected to contain plain data. ]]>
