T09 · Insecure Skill Coding Practices
Warning
- Location
- main.py:902
- Finding
- Spreadsheet Formula Injection in CSV Exports<![CDATA[ ## Vulnerability Details **File Location**: `main.py:902-927` and `main.py:985-1002` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python def import_csv(csv_content: str) -> Tuple[int, List[str]]: """Import IP assets from CSV content.""" lines = csv_content.strip().split('\n') reader = csv.DictReader(io.StringIO(csv_content)) success = 0 errors = [] for row_num, row in enumerate(reader, start=2): if not row.get('ip_no', '').strip(): errors.append(f"Row {row_num} is missing ip_no") continue try: add_asset({ 'ip_no': row.get('ip_no', ''), 'title': row.get('title', ''), 'type': row.get('type', 'patent'), 'sub_type': row.get('sub_type', 'invention'), 'country': row.get('country', 'CN'), 'filing_date': row.get('filing_date', ''), 'grant_date': row.get('grant_date', ''), 'next_fee_date': row.get('next_fee_date', ''), 'status': row.get('status', 'Unknown'), 'owner': row.get('owner', ''), 'notes': row.get('notes', ''), }) success += 1 except Exception as e: errors.append(f"Import failed on row {row_num}: {e}") return success, errors ``` ```python def export_assets_csv() -> str: """Export the IP asset ledger as CSV.""" assets = load_assets() if not assets: return "No IP asset data" output = io.StringIO() fieldnames = ['ip_no', 'title', 'type', 'sub_type', 'country', 'filing_date', 'grant_date', 'next_fee_date', 'status', 'owner', 'inventor', 'notes'] writer = csv.DictWriter(output, fieldnames=fieldnames) writer.writeheader() for asset in assets: writer.writerow({k: asset.get(k, '') for k in fieldnames}) return outp ...[truncated 2644 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Neutralize formula-prefixed values before writing any user-controlled field to CSV: ```python def sanitize_csv_cell(value: Any) -> str: text = '' if value is None else str(value) if text.startswith(('=', '+', '-', '@')): return "'" + text return text ``` Apply it to every exported field: ```python for asset in assets: writer.writerow({ key: sanitize_csv_cell(asset.get(key, '')) for key in fieldnames }) ``` 2. Account for leading whitespace and control characters that may be ignored by spreadsheet clients. A stricter implementation should detect formula prefixes after tabs, carriage returns, line feeds, or leading spaces. 3. Apply protection at export time even if validation is also added during import. Stored records may originate from other interfaces or pre-existing JSON data. 4. Document that exported files can contain user-controlled content and should be opened using protected-view settings. 5. Add regression tests covering values beginning with `=`, `+`, `-`, `@`, tab characters, carriage returns, and line feeds. ]]>
