T09 · Insecure Skill Coding Practices
- Location
scripts/generate_xlsx.py:69- Finding
Excel Formula Injection Through Untrusted Workbook Cell Values
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_xlsx.py, lines 69-74, 115-118, 140-143, 154-158, and 182-184
Vulnerability Type: Spreadsheet formula injection
Risk Level: MediumVulnerable Code
Check-list values are written directly to workbook cells:
python for col, value in enumerate(values, 1): cell = ws.cell(row=row_idx, column=col, value=value) _apply_cell(cell, row_fill) if col == 9 and value in SEVERITY_FILLS: cell.fill = SEVERITY_FILLS[value] if value == "Critical": cell.font = Font(bold=True, color="FFFFFF")Summary values are also written without sanitization:
python for idx, (label, value) in enumerate(sections, 1): if label: ws.cell(row=idx, column=1, value=label).font = Font(bold=True, size=11) ws.cell(row=idx, column=2, value=value).alignment = Alignment(wrap_text=True)Revision-history values are handled in the same manner:
python for row_idx, rev in enumerate(revisions, 2): for col, key in enumerate(["version", "date", "author", "description", "reviewer", "status"], 1): cell = ws.cell(row=row_idx, column=col, value=rev.get(key, "")) _apply_cell(cell)External-reconciliation values are written directly:
python for row_idx, item in enumerate(items, 2): for col, key in enumerate( ["recon_id", "data_source", "provider", "key_fields", "method", "frequency", "discrepancy_handling", "responsible_party", "notes"], 1 ): _apply_cell(ws.cell(row=row_idx, column=col, value=item.get(key, "")))Template mode contains an additional direct-write sink:
python for row_idx, check in enumerate(input_data.get("checks", []), 2): for col_idx, field_name in header_to_field.items(): check_sheet.cell(row=row_idx, column=col_idx + 1, value=check.get(field_name, ""))Technical Analysis
The ...[truncated 3297 chars]
- Remediation
View remediation
Remediation Suggestions
Introduce one centralized conversion function and apply it to every value derived from JSON or user-provided content before assigning it to a workbook cell:
python FORMULA_PREFIXES = ("=", "+", "-", "@") def safe_excel_text(value): if not isinstance(value, str): return value # Account for control characters that spreadsheet applications may # ignore before recognizing a formula. normalized = value.lstrip("\t\r\n") if normalized.startswith(FORMULA_PREFIXES): return "'" + value return valueReplace every untrusted cell assignment with the sanitized value:
python cell = ws.cell( row=row_idx, column=col, value=safe_excel_text(value), )Apply the same protection to:
- Check-list fields.
- Summary values and role entries.
- Revision-history fields.
- External-data reconciliation fields.
- All values written through template column mappings.
Additional hardening measures:
- Treat all imported DVP content as text by default; allow formulas only through an explicit, trusted allowlist.
- Keep pre-existing formulas in a trusted user template separate from values imported from JSON.
- Validate the generated workbook before distribution by loading it and rejecting unexpected cells whose
data_typeisf. - Add automated tests for values beginning with
=,+,-,@, tabs, carriage returns, and newlines. - Test every affected section in both default and template generation modes.
- Document that generated workbooks must not contain formulas originating from study materials or other untrusted input.
