T09 · Insecure Skill Coding Practices
- Location
scripts/normalize_admission_data.py:67- Finding
Spreadsheet Formula Injection in Generated CSV Files
- Content
View full analysis
Vulnerability Details
File Location:
scripts/normalize_admission_data.py:67-76,scripts/shortlist_builder.py:43-47, andscripts/risk_scoring.py:49-53
Vulnerability Type: CSV formula injection
Risk Level: MediumVulnerable Code
scripts/normalize_admission_data.py:67-76:python for row in reader: normalized_row = {field: "" for field in output_fields} for raw_key, value in row.items(): key = field_map.get(raw_key or "", raw_key or "") text = (value or "").strip() normalized_row[key] = clean_number(text) if key in NUMERIC_FIELDS else text rows.append(normalized_row) with outfile.open("w", encoding="utf-8", newline="") as dst: writer = csv.DictWriter(dst, fieldnames=output_fields) writer.writeheader() writer.writerows(rows)scripts/shortlist_builder.py:43-47:python rows.sort(key=lambda r: abs(int(float(r["min_rank"])) - args.rank)) with args.out.open("w", encoding="utf-8", newline="") as dst: writer = csv.DictWriter(dst, fieldnames=fields) writer.writeheader() writer.writerows(rows[: args.limit])scripts/risk_scoring.py:49-53:python rows.sort(key=lambda r: (["冲", "小冲", "稳", "保", "垫"].index(r["risk_band"]), abs(float(r["gap_ratio"])))) with outfile.open("w", encoding="utf-8", newline="") as dst: writer = csv.DictWriter(dst, fieldnames=fields) writer.writeheader() writer.writerows(rows)Technical Analysis
The scripts accept externally supplied admission CSV files and preserve nonnumeric cell contents without neutralizing spreadsheet formula prefixes. Values beginning with
=,+,-, or@can therefore survive normalization, shortlisting, and risk scoring unchanged.Python's
csvmodule correctly quotes CSV syntax but does not prevent spreadsheet applications from interpreting cell values as formulas. If a generated file is opened in software such as ...[truncated 1684 chars]- Remediation
View remediation
Remediation Suggestions
- Sanitize every untrusted text cell before writing it to a CSV intended for spreadsheet use.
- Prefix values whose first non-whitespace character is
=,+,-, or@with an apostrophe or another documented neutralization marker. - Apply the protection consistently in all CSV-producing scripts rather than only in the normalization stage, because users may invoke the tools independently.
- Consider a shared helper such as:
python DANGEROUS_FORMULA_PREFIXES = ("=", "+", "-", "@") def spreadsheet_safe(value: str) -> str: if value.lstrip().startswith(DANGEROUS_FORMULA_PREFIXES): return "'" + value return value- Preserve legitimate negative numbers only for fields explicitly validated as numeric. Treat arbitrary text fields beginning with
-as potentially unsafe. - Document whether output is intended for machine processing or direct spreadsheet viewing.
- Add regression tests covering all dangerous prefixes, leading whitespace, tabs, and payloads in every text column.
