T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/gmaps_leads_export.py:45
- Finding
- Spreadsheet Formula Injection in CSV and XLSX Exports## Vulnerability Details **File Location**: `scripts/gmaps_leads_export.py`, lines 45–50, 63–69, and 96–112 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python for r in rows: ws.append([r.get(h, "") for h in headers]) ``` ```python with out_path.open("w", newline="", encoding="utf-8") as f: w = csv.DictWriter(f, fieldnames=headers) w.writeheader() w.writerows(rows) ``` ```python name = pl.get("name", "") website = d.get("website", "") rows.append( { "name": name, "address": d.get("formatted_address") or pl.get("formatted_address", ""), "phone": d.get("formatted_phone_number") or d.get("international_phone_number", ""), "website": website, "email": "", # website crawl optional step; keep empty by default "rating": d.get("rating") if d.get("rating") is not None else pl.get("rating", ""), "place_id": pid, "google_maps_url": f"https://www.google.com/maps/search/?api=1&query={quote_plus(name)}&query_place_id={pid}", } ) ``` ### Technical Analysis Business names, addresses, phone numbers, websites, ratings, and place identifiers are obtained from external MCP/Google Maps responses. The script writes these values directly to CSV or XLSX cells without neutralizing spreadsheet formula prefixes. Values beginning with characters such as `=`, `+`, `-`, or `@` may be interpreted as formulas when the export is opened in spreadsheet software. In XLSX output, `openpyxl` can store a string beginning with `=` as a formula rather than literal text. CSV applications may similarly evaluate formula-like fields when opening the file. Consequently, an attacker who can influence a Google Maps listing field could inject a spreadsheet expression into an exported lead record. ### Attack Path 1. An attacker creates or modifies a Google Maps business listing so that an exported field contains a spreadsheet formula, such as a value beginnin ...[truncated 1300 chars]
- Remediation
- ## Remediation Suggestions Introduce a centralized sanitizer and apply it to every externally sourced value before both CSV and XLSX export. 1. Treat values beginning with `=`, `+`, `-`, or `@` as potentially dangerous. Also account for leading tabs, carriage returns, newlines, and whitespace that spreadsheet clients may ignore before formula detection. 2. Prefix dangerous textual values with a single quotation mark or otherwise encode them as literal text. 3. For XLSX output, explicitly set externally sourced cells to text and apply a text number format. Do not rely exclusively on visual formatting to suppress formula evaluation. 4. Preserve trusted, locally constructed hyperlinks only after validating their components. Validate `place_id` before incorporating it into the generated Google Maps URL. 5. Apply the protection to all exported columns, not only the fields currently expected to contain free-form text. 6. Add regression tests covering values such as `=1+1`, `+SUM(1,1)`, `-1+2`, `@SUM(1,1)`, and formula prefixes preceded by tabs or carriage returns. 7. Document that generated spreadsheets contain externally sourced business data and should not be opened with legacy external-content or macro features enabled. A sanitizer can follow this pattern: ```python FORMULA_PREFIXES = ("=", "+", "-", "@") def spreadsheet_safe(value): if value is None: return "" text = str(value) probe = text.lstrip(" \t\r\n") if probe.startswith(FORMULA_PREFIXES): return "'" + text return text ``` Apply `spreadsheet_safe` to every field passed to `csv.DictWriter` and every externally sourced cell appended through `openpyxl`.
