T09 · Insecure Skill Coding Practices
- Location
scripts/writer.py:120- Finding
Untrusted Input Can Produce Active Excel Formulas
- Content
View full analysis
Vulnerability Details
File Locations:
scripts/writer.py:120-130scripts/pairwise.py:249-253
Vulnerability Type: Spreadsheet formula injection
Risk Level: MediumVulnerable Code
In
scripts/writer.py:120-130, values derived from requirement documents or input JSON are written directly to workbook cells:python row_data = [ seq_num, case_id, priority, test_dim, case_type, domain, design, scenario, test_point, steps_text, expected_text, test_data, precondition, req_source, "", ] for col, value in enumerate(row_data, 1): cell = ws.cell(row=row, column=col, value=value) cell.font = BASE_FONT cell.alignment = WRAP cell.border = BORDERThe same pattern occurs in
scripts/pairwise.py:249-253:python for j, name in enumerate(names): cell = ws.cell(row=i, column=j + 2, value=str(row.get(name, ""))) cell.font = BASE_FONT cell.alignment = WRAP cell.border = BORDERTechnical Analysis
Both Excel exporters treat externally supplied text as trusted cell content. No validation or neutralization is applied to values beginning with spreadsheet formula indicators such as
=,+,-, or@.Openpyxl normally stores an
=-prefixed string as a formula rather than literal text. Consequently, an attacker-controlled requirement, test-case field, parameter name, or pairwise parameter value can become an active formula in the generated workbook.The vulnerability crosses a trust boundary because source documents and JSON inputs may be supplied by third parties, while the generated workbook is expected to be opened by a reviewer. Formula execution behavior depends on the spreadsheet application and its security configuration.
Attack Path
- An attacker creates a requirement document or JSON input containing a formula-like value, such as an external-reference or hyperlink formula.
- The Skill extracts or preserves ...[truncated 1286 chars]
- Remediation
View remediation
Remediation Suggestions
-
Introduce a centralized cell-sanitization function and apply it to every externally derived textual value:
python def sanitize_excel_text(value): if value is None: return "" if not isinstance(value, str): return value if value.startswith(("=", "+", "-", "@")): return "'" + value return value -
Call this function before every untrusted value is assigned to a workbook cell:
python safe_value = sanitize_excel_text(value) cell = ws.cell(row=row, column=col, value=safe_value) -
Apply equivalent protection in
pairwise.pyto parameter names, headers, and parameter values. -
Consider also protecting values whose first non-whitespace character is a formula indicator:
python if value.lstrip().startswith(("=", "+", "-", "@")): return "'" + value -
Preserve numeric fields as numeric values, but explicitly treat all document-derived descriptive fields as text.
-
Add regression tests covering formula prefixes, leading whitespace, tabs, carriage returns, and Unicode control characters.
-
Document that generated workbooks should be opened with external links and active content disabled.
-
