T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/generate_stock_excel.py:33
- Finding
- Spreadsheet Formula Injection in Generated Excel Workbooks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_stock_excel.py`, lines 33–37 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python with pd.ExcelWriter(output_file, engine='openpyxl') as writer: for sheet in sheets_data: df = pd.DataFrame(sheet['rows'], columns=sheet['headers']) # Excel sheet name max 31 chars sheet_name = sheet['name'][:31] df.to_excel(writer, sheet_name=sheet_name, index=False) ``` ### Technical Analysis The script places headers and row values directly into a Pandas DataFrame and exports them to an Excel workbook without neutralizing formula-like strings. The intended workflow populates these fields with externally retrieved stock-query data, while direct command-line invocation also permits a caller to supply arbitrary cell values. In particular, a string beginning with `=` can be stored as an Excel formula by the `openpyxl` export engine rather than as literal text. Other spreadsheet formats or applications may also interpret values beginning with `+`, `-`, or `@` as formulas. An attacker who controls a returned field or invocation argument could inject a formula such as an external reference, deceptive hyperlink, or another supported spreadsheet expression. Formula behavior depends on the spreadsheet application and its security settings; some external operations may require user confirmation or may be disabled by default. ### Attack Path 1. An attacker controls stock-query content, another data source used by the Skill, or arguments passed directly to the script. 2. The attacker places a formula-prefixed string in a header or row value. 3. The value is inserted into `sheet['headers']` or `sheet['rows']`. 4. `df.to_excel()` writes the value without converting it to safe literal text. 5. A user opens the generated workbook in a spreadsheet application. 6. The application evaluates the formula or displays an interaction pr ...[truncated 825 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Sanitize all externally sourced headers and cell values before creating the DataFrame: 1. Treat strings whose first non-whitespace character is `=`, `+`, `-`, or `@` as potentially unsafe. 2. Prefix unsafe values with a single quote or otherwise force the destination cell type to literal text. 3. Apply sanitization recursively to every header and row value, not only selected display columns. 4. If CSV export is implemented, apply the same protection because CSV files are also susceptible to spreadsheet formula injection. 5. Add tests covering leading whitespace, tabs, newlines, and each formula marker. Example hardening logic: ```python def safe_spreadsheet_value(value): if isinstance(value, str) and value.lstrip().startswith(('=', '+', '-', '@')): return "'" + value return value safe_headers = [safe_spreadsheet_value(v) for v in sheet['headers']] safe_rows = [ [safe_spreadsheet_value(v) for v in row] for row in sheet['rows'] ] df = pd.DataFrame(safe_rows, columns=safe_headers) ``` Where possible, explicitly configure exported cells as text and validate the resulting workbook to ensure formula cells are not created from untrusted data. ]]>
