T09 · Insecure Skill Coding Practices
- Location
scripts/build_ig_recruiting_outreach.py:134- Finding
Untrusted CSV Fields Are Exported Without Spreadsheet Formula Neutralization
- Content
View full analysis
Vulnerability Details
File Location:
scripts/build_ig_recruiting_outreach.py, lines 134-155
Vulnerability Type: CSV formula injection
Risk Level: MediumVulnerable Code
python def write_messages_csv(path: Path, campaign: str, sequences: List[Dict[str, object]]) -> None: with path.open("w", encoding="utf-8", newline="") as f: writer = csv.DictWriter( f, fieldnames=[ "campaign", "instagram_handle", "target_brokerage", "stage", "message", ], ) writer.writeheader() for seq in sequences: lead = seq["lead"] # type: ignore[index] for item in seq["messages"]: # type: ignore[index] writer.writerow( { "campaign": campaign, "instagram_handle": lead["handle"], "target_brokerage": lead["target_brokerage"], "stage": item["stage"], "message": item["message"], } )Technical Analysis
The function writes values derived from command-line arguments and the input lead CSV directly into an output CSV. In particular,
campaignandlead["target_brokerage"]are not neutralized before export.CSV quoting performed by Python's
csvmodule protects the file structure but does not prevent spreadsheet formula interpretation. When a cell begins with a formula indicator such as=,+,-, or@, spreadsheet software may process it as a formula rather than plain text. Leading tab or carriage-return characters can also be used to bypass incomplete validation.An attacker who can influence a lead record could therefore provide a crafted
target_brokeragevalue. The generatedmessages_<campaign>.csvwould retai ...[truncated 1453 chars]- Remediation
View remediation
Remediation Suggestions
Introduce a centralized CSV-cell neutralization function and apply it to every untrusted or externally influenced field before calling
writer.writerow().The hardening function should:
- Treat values beginning with
=,+,-, or@as potentially dangerous. - Also account for leading tabs, carriage returns, line feeds, and whitespace followed by a formula indicator.
- Prefix dangerous values with an apostrophe or use another neutralization approach documented as safe for the spreadsheet applications supported by the workflow.
- Preserve the original value separately in JSON if exact, machine-readable source data is required.
- Apply protection to all exported fields rather than only
target_brokerage, because future changes may allow additional fields to begin with attacker-controlled content. - Add regression tests covering every dangerous prefix, leading whitespace/control characters, quoted payloads, and ordinary benign values.
- Document that generated CSV files contain untrusted lead data and should be imported with formula execution disabled where possible.
Example defensive implementation:
python FORMULA_PREFIXES = ("=", "+", "-", "@", "\t", "\r", "\n") def safe_csv_cell(value: object) -> str: text = str(value) probe = text.lstrip(" ") if probe.startswith(FORMULA_PREFIXES): return "'" + text return textEvery value in the row should then be passed through
safe_csv_cell()before export. This function should be validated against the behavior of the spreadsheet applications used by campaign operators.- Treat values beginning with
