T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/交易记录.py:121
- Finding
- Untrusted spreadsheet data is written as executable formulas<![CDATA[ ## Vulnerability Details **File Location**: `scripts/交易记录.py:121-137`, `scripts/交易记录.py:169-179`, `scripts/交易记录.py:342-346`; `scripts/生成账目.py:405-426` **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: High ### Vulnerable Code ```python # scripts/交易记录.py:121-137 ws_checking = wb.create_sheet(title='招行活期') ws_checking.append(['交易日期', '收入', '支出', '余额', '交易备注']) for row in checking_data: ws_checking.append([row['date'], row['income'], row['expense'], row['balance'], row['note']]) # 2. 招行理财 ws_finance = wb.create_sheet(title='招行理财') if finance_data: # 添加标题行(从原始数据获取) headers = ['委托状态', '委托日期', '代码', '货币', '交易类型', '委托数量', '成交价格', '委托金额', '交易金额', '已提业绩报酬', '确认份额日期', '资金到账日期', '合同号', '交易详情'] ws_finance.append(headers) for item in finance_data: ws_finance.append(list(item['raw'])) ``` ```python # scripts/交易记录.py:169-179 ws_corp.append([ date_str, convert_value(row[2]) if len(row) > 2 else None, # 收入(贷方) convert_value(row[1]) if len(row) > 1 else None, # 支出(借方) convert_value(row[3]) if len(row) > 3 else None, # 余额 row[6] if len(row) > 6 else '' # 账号/摘要 ]) ``` ```python # scripts/交易记录.py:342-346 else: for j, val in enumerate(row, 1): # 把 0 改为 None(显示为空) if val == 0: val = None cell = ws_print.cell(row=i, column=j, value=val) ``` ```python # scripts/生成账目.py:405-426 row_num = ws.max_row + 1 if row_data['balance_formula']: balance_val = row_data['balance_formula'] else: # 所有行都用公式:=上期 + 本行收入 - 本行支出 balance_val = f'=A{row_num-1}+F{row_num}-G{row_num}' row = [ balance_val, # A 列:余额 row_data['date'], # B 列:发生日期 row_data['cat1'], # C 列:分类 1 row_data['cat2'], # D 列:分类 2 row_data['cat3'], # E 列:分类 3 row_data['income'], # F 列:收入金额 row_data['expense'], # G 列:支出金额 h_value, # H 列:应付/应收/预收 row_data['note'], # I 列:备注 row_data['student'], # J 列:学员/单位 row_data['acco ...[truncated 2515 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Introduce a centralized function for writing imported text safely: ```python def safe_spreadsheet_text(value): if not isinstance(value, str): return value if value.startswith('='): return "'" + value return value ``` 2. Apply this function to every untrusted textual field before passing it to `append()` or assigning it to `Cell.value`, including: - Checking-account notes and dates. - Corporate-account summaries. - Every raw finance-workbook text field. - Notes and other textual fields copied by the accounting generator. 3. Do not propagate formulas from imported workbooks. Replace: ```python if row_data['balance_formula']: balance_val = row_data['balance_formula'] ``` with logic that discards imported formulas and calculates balances exclusively using internally generated, structurally fixed formulas. 4. Load source workbooks with `data_only=True` when only cached values are required. This reduces accidental formula propagation, although it must not replace output sanitization because cached values may be unavailable. 5. Separate trusted application formulas from imported values at the data-model level. For example, use a dedicated formula wrapper that can only be constructed by internal calculation code. 6. Add regression tests using notes and cells such as `=1+1`, `=HYPERLINK(...)`, and external-reference formulas. Verify that imported values are stored as literal strings while internally generated balance formulas remain formulas. ]]>
