T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/generate_band_offer_packet.js:18
- Finding
- CSV Formula Injection in Compensation Offer Export## Vulnerability Details **File Location**: `scripts/generate_band_offer_packet.js:18-22`, with the vulnerable export used at line 204 **Vulnerability Type**: CSV formula injection **Risk Level**: Medium ### Vulnerable Code ```js function csvEscape(value) { const str = safe(value); if (str.includes(",") || str.includes("\"") || str.includes("\n")) return `"${str.replace(/"/g, "\"\"")}"`; return str; } ``` The function is subsequently applied to user-controlled compensation fields: ```js fs.writeFileSync(trackerPath, `${header.join(",")}\n${row.map(csvEscape).join(",")}\n`, "utf8"); ``` ### Technical Analysis The `csvEscape` function implements delimiter and quotation escaping, but it does not neutralize spreadsheet formula prefixes. Values beginning with `=`, `+`, `-`, `@`, tab, or carriage return can be interpreted as formulas when the generated CSV is opened in spreadsheet software. Several exported fields originate from user-supplied JSON, including the candidate name, target role, expected compensation, and generated recommendation fields. Consequently, an attacker able to influence the input JSON could insert a formula payload into an exported cell. Quoting a malicious value is insufficient because common spreadsheet applications can still evaluate quoted CSV cells as formulas. ### Attack Path 1. An attacker supplies or modifies a compensation-review JSON document. 2. A user-controlled field, such as `candidate_name` or `job_title`, is set to a spreadsheet formula, for example a formula that creates a deceptive hyperlink or initiates a network request. 3. HR runs the documented command to generate the compensation packet. 4. `csvEscape` preserves the formula prefix and writes it to `band-offer-review.csv`. 5. A recipient opens the CSV in a spreadsheet application. 6. Depending on the spreadsheet client and its security configuration, the formula may be evaluated or presented as an actionabl ...[truncated 695 chars]
- Remediation
- ## Remediation Suggestions 1. Detect values whose first significant character is `=`, `+`, `-`, or `@`, as well as values beginning with tab or carriage return. 2. Prefix such values with an apostrophe before applying ordinary CSV quoting. 3. Apply the protection to every externally influenced cell, not only names or free-text fields. 4. Consider generating XLSX instead of CSV and explicitly assign affected cells the string data type. 5. Add regression tests covering formulas both with and without leading whitespace. Example hardening: ```js function csvEscape(value) { let str = safe(value); if (/^[\t\r ]*[=+\-@]/.test(str)) { str = `'${str}`; } if (/[",\n\r]/.test(str)) { return `"${str.replace(/"/g, "\"\"")}"`; } return str; } ```
