T09 · Insecure Skill Coding Practices
- Location
rebar_table_audit/report.py:127- Finding
Spreadsheet Formula Injection Through Untrusted CAD Text
- Content
View full analysis
Vulnerability Details
File Location:
rebar_table_audit/report.py:127-160; input originates fromrebar_table_audit/extract.py:195-201
Vulnerability Type: Spreadsheet formula injection
Risk Level: MediumTechnical Analysis
Text extracted from externally supplied DWG or DXF entities is preserved without neutralizing spreadsheet formula prefixes:
python raw_text = _text_string(entity) if raw_text is None or raw_text.strip() == "": return x, y = _text_position(entity) normalized = normalize_text(raw_text) result.texts.append(TextItem( text=normalized, raw=raw_text, x=x, y=y, height=_text_height(entity), handle_path=handle_path, layout=layout_name, ))Parsed drawing values, including the table title, mark, and position, are then passed directly to openpyxl worksheet cells:
python for row in _grade_summary(evidence["tables"]): ws_sum.append([ row["table_id"], row["title"], row["grade"], row["row_sum_kg"], row["declared_kg"], row["diff_kg"], ])python for t in evidence["tables"]: for r in t["rows"]: p = r["parsed"] handles = ";".join(sorted({h for c in r["cells"] for h in c["handles"]})) ws_detail.append([ t["id"], p["mark"], p["position"], p["grade"], p["grade_source"], p["diameter_mm"], p["single_length_m"], p["count"], p["total_length_m"], p["weight_kg"], p["unit_weight_kg_per_m"], handles, ])openpyxl treats strings beginning with
=as formulas when saving a workbook. The code performs Unicode normalization but does not neutralize formula-leading characters before placing drawing-derived strings into spreadsheet cells.This crosses a trust boundary because content authored by an independent CAD document provider is transferred into an interpretation-ca ...[truncated 1761 chars]
- Remediation
View remediation
Remediation Suggestions
Introduce a centralized function for all externally derived spreadsheet strings and apply it before every worksheet write:
python def spreadsheet_literal(value): if not isinstance(value, str): return value if value.startswith(("=", "+", "-", "@")): return "'" + value return valueApply the function to table titles, marks, positions, grades, finding messages, gap messages, symbol mappings, raw text, and every other value derived from a drawing or custom mapping file.
For stronger guarantees, explicitly set externally derived cells to the string data type rather than relying solely on prefix handling. Keep numeric values generated by trusted parsing logic numeric where calculations or sorting are required.
Add regression tests that generate a workbook from drawing fields beginning with
=,+,-, and@, reload it with openpyxl, and verify that the resulting cells are literal strings rather than formulas. Tests should include representative payloads such as=HYPERLINK(...)and confirm that legitimate negative numeric values remain numeric.
