T09 · Insecure Skill Coding Practices
- Location
SKILL.md:94- Finding
Spreadsheet Formula Injection Through Untrusted Cell Values
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 94–130
Vulnerability Type: Spreadsheet formula injection
Risk Level: MediumVulnerable Code Segments
Product data derived from user input, lines 94–102:
markdown 1. 从用户输入中提取需要报价的产品名称列表。 2. 在已解析的物料价格表中查找每个产品: - 若一个 `materialName` 只对应一个 `specModel` → 直接确定 - 若一个 `materialName` 对应多个 `specModel` → **必须向用户发起澄清**,列出所有可选型号及对应价格,请用户确认 3. **澄清规则**: - 若用户已在消息中明确指定了型号 → 视为已澄清,直接继续 - 若当前消息是对上一轮澄清的补充(提供了缺失的型号/品牌/规格)→ 视为澄清完成,**禁止再次发起澄清**,继续执行后续流程 - 需要澄清的产品必须是物料价格表中真实存在的,禁止自行创造 - 如果用户输入的产品在物料表中**找不到**,也要告知用户"未找到该产品,请检查名称或补充到物料表中"Untrusted values placed into fill operations, lines 107–117:
markdown 1. 根据确认后的产品-型号-单价映射,结合模板列映射,生成填充数据: - 行号规则:第 N 条产品行 = `start_row + N` - **严禁** 把产品写在 `start_row`(表头行),必须从 `start_row + 1` 开始 - 数量默认填 `1`,若用户在输入中明确指定了数量则使用指定值 2. 计算总价: - 若模板金额列已有公式 → 只填数量和单价,让公式自动计算 - 若模板金额列无公式 → 计算 `数量 × 单价` 填入金额列 3. 填充单值区域: - 客户名称、日期、报价单号等,若用户提供则填入对应位置 - 日期默认为当天,格式与模板中原有日期格式保持一致 4. 输出 `fill_operations` 结构,参见 [references/data-schema.md](references/data-schema.md)。Direct workbook writes without sanitization, lines 124–130:
markdown 1. 复制用户上传的模板到临时目录,生成唯一文件名(UUID 后缀)。 2. 使用 `openpyxl` 遍历 `fill_operations`,写入对应单元格: - `col` 用 `column_index_from_string()` 转为列索引 - `row` 必须 > 0,`col` 不能为空 - 对于已有公式的单元格,若需要覆盖,先清除原有公式再写入值 3. 保存工作簿,返回生成文件的路径和名称。Technical Analysis
The workflow accepts text from user messages and uploaded Excel or CSV price lists, places that text into
fill_operations, and then writes each value directly to an Excel workbook throughopenpyxl. No validation or output encoding is specified for text beginning with spreadsheet formula markers.In particular, a string beginning with
=can be stored byopenpyxlas a formula rather than as literal text. Other leading characters commonly associated with spreadshe ...[truncated 2447 chars]- Remediation
View remediation
Remediation Suggestions
- Separate trusted formulas from untrusted text. Permit formulas only in explicitly identified template formula cells. Values originating from users, CSV files, or uploaded workbooks must be written as literal text.
- Sanitize dangerous prefixes. Before writing an untrusted string, normalize and inspect its first meaningful character. Treat
=,+,-, and@as dangerous, including when preceded by spaces, tabs, carriage returns, line feeds, or other control characters. - Force literal cell values. Prefix dangerous values with a single quote or explicitly set the cell to a string type using a safe helper designed for the selected Excel library. Verify that the chosen method remains literal after saving and reopening the workbook.
- Validate formula cells with an allowlist. Preserve or generate formulas only for expected fields such as the total-price column. Validate generated formulas against a strict pattern, such as multiplication of the quantity and unit-price cells on the same row.
- Do not copy formulas from untrusted source data. When parsing uploaded workbooks, distinguish formulas from displayed values and reject formulas in fields expected to contain names, models, units, remarks, or identifiers.
- Apply field-specific validation. Require numeric fields to parse as bounded numeric values and restrict identifier fields such as quotation numbers to an appropriate character allowlist.
- Add regression tests. Test direct and whitespace-prefixed payloads beginning with
=,+,-, and@. Save and reopen each generated workbook to confirm that untrusted values remain literal strings while approved template formulas continue to work. - Document the trust boundary. State explicitly that uploaded price lists, quotation templates, and user-provided metadata are untrusted and must not introduce new executable spreadsheet expressions.
