T09 · Insecure Skill Coding Practices
- Location
SKILL.md:390- Finding
Spreadsheet Formula Injection Through Unsanitized OCR Data
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 390–401
Vulnerability Type: Spreadsheet formula injection
Risk Level: MediumVulnerable Code
python ws[f'A{last_row}'] = invoice_data.get('entry_date', date.today()) ws[f'B{last_row}'] = invoice_data.get('invoice_code') ws[f'C{last_row}'] = invoice_data.get('invoice_number') ws[f'D{last_row}'] = invoice_data.get('product_name') ws[f'E{last_row}'] = invoice_data.get('spec') ws[f'F{last_row}'] = invoice_data.get('quantity') ws[f'G{last_row}'] = invoice_data.get('unit_price') ws[f'H{last_row}'] = invoice_data.get('amount') ws[f'I{last_row}'] = invoice_data.get('tax_amount') ws[f'J{last_row}'] = invoice_data.get('total_amount') ws[f'K{last_row}'] = invoice_data.get('seller_name') ws[f'L{last_row}'] = invoice_data.get('purchase_order_no')Technical Analysis
The function writes OCR-derived invoice fields directly into Excel cells without validating their expected types or neutralizing spreadsheet formula prefixes. Text beginning with
=,+,-, or@may be interpreted as a formula by Excel or another spreadsheet client rather than as literal invoice data.An attacker who controls invoice content could place a formula-like payload in fields such as the product name, specification, seller name, or purchase-order number. If OCR preserves that content,
openpyxlstores it in the workbook without a protective literal-text prefix. The payload may then be evaluated when a finance user opens the workbook.The precise behavior depends on the spreadsheet client and its security configuration. Potential payloads include deceptive formulas, malicious hyperlinks, and formulas that attempt external-data access. There is no evidence in the audited project of direct operating-system command execution; such an outcome would require additional client-specific unsafe features or user interaction.
Attack Path
- An attacker creates or modifies an invoice image containing formula-prefi ...[truncated 1347 chars]
- Remediation
View remediation
Remediation Suggestions
- Apply centralized sanitization to every untrusted value before writing it to a spreadsheet:
python def excel_safe(value): if isinstance(value, str): value = value.strip() if value.startswith(("=", "+", "-", "@")): return "'" + value return value- Use the sanitizer for all OCR-derived textual fields:
python ws[f'D{last_row}'] = excel_safe(invoice_data.get('product_name')) ws[f'E{last_row}'] = excel_safe(invoice_data.get('spec')) ws[f'K{last_row}'] = excel_safe(invoice_data.get('seller_name')) ws[f'L{last_row}'] = excel_safe(invoice_data.get('purchase_order_no'))-
Enforce field-specific validation:
- Require invoice codes and numbers to match documented numeric formats.
- Parse monetary values, quantities, and tax rates into numeric types before writing them.
- Apply length and character restrictions to names, specifications, and order identifiers.
- Reject values containing control characters or unexpected formula syntax.
-
Treat all OCR output as untrusted, even if the source resembles an official invoice.
-
Add regression tests covering values beginning with
=,+,-, and@, including malicious hyperlinks and external-reference formulas. -
Document that generated workbooks contain imported content and should be opened with external links, macros, and automatic data updates disabled.
