T09 · Insecure Skill Coding Practices
Warning
- Location
- create_xlsx.py:115
- Finding
- Untrusted JSON Values Can Be Embedded as Active Spreadsheet Formulas<![CDATA[ ## Vulnerability Details **File Location**: `create_xlsx.py`, lines 115–127 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python def populate_sheet_from_data(worksheet, sheet_data: dict[str, Any]) -> None: headers = sheet_data.get("headers", []) rows = sheet_data.get("rows", []) title = sheet_data.get("title") if title: worksheet.title = str(title)[:31] if headers: for col, header in enumerate(headers, start=1): worksheet.cell(row=1, column=col, value=header) style_header_row(worksheet, 1, len(headers)) start_row = 2 if headers else 1 for row_index, row_values in enumerate(rows, start=start_row): for col_index, value in enumerate(row_values, start=1): worksheet.cell(row=row_index, column=col_index, value=value) autosize_columns(worksheet) ``` ### Technical Analysis Values obtained from the input JSON are passed directly to `openpyxl` cells without distinguishing ordinary text from spreadsheet formulas. In particular, a string beginning with `=` is stored by `openpyxl` as a formula rather than as literal text. An attacker who can influence the JSON input can therefore insert formulas such as `=HYPERLINK(...)`, external workbook references, or deceptive expressions. The resulting workbook appears to be an ordinary generated document, but attacker-controlled formulas may be evaluated when a recipient opens or refreshes it. This is a data-to-code interpretation flaw in the spreadsheet output layer. No shell or Python code execution occurs in the generator itself, but untrusted input becomes active content in the recipient's spreadsheet application. ### Attack Path 1. An attacker supplies or influences a JSON data file accepted through the `--data` option. 2. The attacker places a formula string in a row value, for example: ```json { "headers": ["Description", "Link"], "rows": [ ["Revi ...[truncated 1288 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Treat JSON-derived strings as literal text by default and allow formulas only through an explicit, separately validated schema. 1. Sanitize imported strings before assigning them to cells: ```python def safe_cell_value(value: Any) -> Any: if isinstance(value, str) and value.startswith(("=", "+", "-", "@")): return "'" + value return value ``` 2. Apply the conversion to both headers and row values: ```python worksheet.cell( row=row_index, column=col_index, value=safe_cell_value(value), ) ``` 3. If formulas are a required feature, represent them with an explicit structure such as: ```json {"type": "formula", "value": "=SUM(B2:B10)"} ``` Formula support should be disabled by default and enabled only for trusted input. Validate permitted functions and prohibit external references, hyperlinks, dynamic data exchange syntax, and unexpected workbook references. 4. Validate that `headers` and `rows` are arrays and that each row is an array before processing them. 5. Add regression tests confirming that values such as `=1+1`, `=HYPERLINK(...)`, `+CMD`, `-1+2`, and `@SUM(...)` are stored and displayed as literal text unless formula processing has been explicitly authorized. ]]>
