cybersecurity · intermediate · ~25 min

Prevent CSV injection by prefixing risky cells

Threat-aware defensive copying.

Challenge

Neutralise a spreadsheet formula-injection payload at export time, so a cell like =cmd|'/c calc'!A0 opens as plain text instead of running.

Task

Implement int sanitize_cell(const char *cell, char *out, size_t cap) that writes a safe version of cell into out (capacity cap, including the NUL).

Input

  • cell: a NUL-terminated cell value the grader passes.
  • out: caller-provided buffer of size cap.

Output

  • If cell starts with =, +, -, or @, prepend one tab \t so spreadsheet apps treat the cell as text; otherwise copy cell unchanged.
  • NUL-terminate out.
  • Return the number of bytes written (excluding the NUL), or -1 if the result plus its NUL would not fit in cap.

Example

sanitize_cell("hello", out, 64)     ->   5,  out = "hello"
sanitize_cell("=SUM(A1)", out, 64)  ->   9,  out = "\t=SUM(A1)"
sanitize_cell("+1234", out, 64)     ->   6,  out = "\t+1234"
sanitize_cell("=A1", tiny, 2)       ->  -1   (does not fit)
sanitize_cell("", out, 64)          ->   0

Edge cases

  • Empty input gets no prefix and returns 0.
  • A cap too small for the result (plus NUL) returns -1 and the buffer must not overflow.

Rules

  • No dynamic allocation — write only into out.

Why this matters

CSV injection (formula injection) is when a malicious value like =cmd|'/c calc'!A0 runs in Excel when a user opens an exported CSV. Excel and LibreOffice still treat leading =, +, -, @ as formulas. Prevent it at export time.

Input format

A NUL-terminated cell, an output buffer out, and its capacity cap.

Output format

Bytes written excluding the NUL, or -1 if the result would not fit.

Constraints

No dynamic allocation; never write past cap.

Starter code

#include <stddef.h>
int sanitize_cell(const char *cell, char *out, size_t cap) { /* TODO */ return -1; }

Common mistakes

Only checking = (Excel formulas also start with +, -, @); prepending a space (Excel sometimes strips it); prepending the tab outside the quoted CSV field (breaks formatting).

Edge cases to handle

Empty input — no prefix. A leading tab already present — still safe to add another (idempotency isn't required).

Complexity

O(strlen).

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.