Keep AI-Exported Text from Becoming Spreadsheet Formulas

Z

ZharfAI Team

September 18, 202611 min read
Keep AI-Exported Text from Becoming Spreadsheet Formulas

A support note contains the literal text =1+1. An AI assistant copies it faithfully into a report. The CSV is well formed, but a recipient opens it through a spreadsheet import path that recognizes formulas and sees 2 instead. The model did not misquote the source. The destination assigned the text a different meaning.

This is a harmless constructed example, not a customer incident. It exposes a practical decision for product engineers and reporting owners: which exported values must remain data, and who is allowed to create executable formulas? That boundary belongs in the file writer and import path. A prompt asking the model to avoid formulas is not an enforcement mechanism.

Two interpreters stand between the note and the cell

A CSV reader first separates records and fields. A spreadsheet application then interprets their contents. Correct quoting can preserve a comma inside a note without requiring the application to treat that note as a literal string. Syntactic correctness and cell semantics are separate properties.

RFC 4180 describes conventional field quoting, including quoted commas or line breaks and doubled embedded quotes. It is an informational document from October 2005, not a spreadsheet cell-type or safety standard. Use a proper CSV writer rather than concatenating values with commas; then address interpretation separately.

OWASP's CSV injection guidance describes the risk of untrusted input becoming spreadsheet formulas. Prefixes such as equals, plus, minus and at-sign, along with certain control characters, matter when assessing a consumer; behavior varies with application and locale. This does not establish that every modern Excel installation automatically executes every historical attack.

The mechanism is distinct from prompt injection. Prompt injection tries to redirect a model; formula injection reaches a spreadsheet interpreter after the model has finished. Faithful copying is therefore not a sufficient defense. A conventional exporter without any AI can have the same defect.

Define column meaning before inspecting suspicious characters

An identifier such as 00123 is not a number to add. A telephone string may legitimately begin with a plus sign. A validated negative quantity may be a correct numeric value, while the same characters inside a customer note should remain text. Rejecting every minus sign confuses safety with data destruction.

ZharfAI's proposed export contract assigns each column a fixed name, type, null policy, length limit, provenance and permitted transformations. Notes, extracted descriptions and identifiers use a string path. Numeric values use a numeric path only after type, range and business-meaning checks. Missing, zero and the word “unknown” remain distinct states.

Structured output helps make those checks possible. It does not make a string beginning with equals trustworthy as code. Our structured-output contract guide separates valid structure from a valid decision; this export boundary adds another requirement: a valid string must not silently acquire formula authority.

Units, currency and rounding remain independent. Preventing formulas does not make a mixed-currency sum meaningful. Establish the quantity and measurement contract before choosing numeric output. Test precision separately for sensitive amounts and long identifiers; spreadsheet numeric types are not a universal arbitrary-precision representation.

Choose a destination, not a universally safe file extension

Ask where the file will go. A machine ingestion service, a person double-clicking an attachment and an integration writing to Google Sheets are different consumers. A later conversion back to CSV creates another interpretation boundary, even if the original workbook had explicit cell types.

Actual destinationProposed choiceRemaining obligation
Human-readable spreadsheet reportXLSX with explicit string and numeric writesInspect writer behavior, package contents and supported applications
Values sent to Google SheetsRAW input with schema-appropriate valuesEnforce access, destination ranges and semantic validation separately
Machine receiving CSVConventional CSV plus a column schema and original valuesUse a known parser without undocumented type inference
Human who requires CSVA documented, tested import procedure for that applicationInclude direct-open and subsequent conversion behavior in the support boundary

This is an engineering recommendation, not a product security ranking. An XLSX file can contain formulas; its extension proves nothing. Its useful property here is that the writer can explicitly represent text. If the recipient's import path is unknown, change the format or narrow the supported use rather than promising safe CSV everywhere.

Do not create two downloads merely for symmetry. A single controlled destination may need one well-defined export. Separate machine and human variants only when literal-data fidelity conflicts with a consumer-specific display workaround. Make that distinction visible in their names and accompanying instructions.

Write strings deliberately instead of relying on convenience inference

XlsxWriter's generic write() dispatches according to input type and also recognizes formula and URL pseudo-types encoded as strings. Its data-writing documentation provides explicit alternatives, including write_string() and write_number(). A note column should use the string writer because its meaning is already known.

The Workbook options reference documents formula and URL conversion as enabled by default for generic writes; string-to-number conversion defaults to disabled. Set all three explicitly when they are unwanted. Those options do not prevent other code from calling an explicit formula writer.

This deliberately small example demonstrates a text-only boundary. It builds a workbook in memory without evaluating formulas. The ten-thousand-character ceiling is an illustrative policy choice, not a claimed product limit:

from io import BytesIO
import xlsxwriter

def text_export(values):
    output = BytesIO()
    options = {
        "in_memory": True,
        "strings_to_formulas": False,
        "strings_to_urls": False,
        "strings_to_numbers": False,
    }
    with xlsxwriter.Workbook(output, options) as book:
        sheet = book.add_worksheet("Report")
        for row, value in enumerate(values):
            if not isinstance(value, str) or not 1 <= len(value) <= 10_000:
                raise ValueError("Expected bounded, non-empty text")
            if sheet.write_string(row, 0, value) != 0:
                raise ValueError("Cell write failed")
    return output.getvalue()

Only deliver bytes after successful workbook closure. This function intentionally rejects nulls and empty strings; a real product must define their representation rather than accidentally adopting this example's policy. The caller also needs row and file-size limits, package-error handling and rules for every other column. This is not a complete enterprise exporter.

Keep headers and sheet names under application-template control. User data should not directly determine file paths or workbook structure. Follow the value through wrappers and later conversions: disabling inference in one library does not help if another layer rewrites the same value using a generic writer or CSV.

Use explicit input semantics in Sheets and Calc

Google's ValueInputOption reference distinguishes RAW, which stores values without parsing, from USER_ENTERED, which applies UI-style interpretation. For untrusted text, the former matches the intended boundary. Validate values against the column contract first: raw input is neither access control nor a correction for bad numbers.

LibreOffice's Text Import documentation exposes formula evaluation, text column types and a quoted-fields-as-text option. The chosen language also affects numeric recognition. A CSV import recipe should specify those choices rather than depending on settings left over from a previous file.

These are documented controls, not proof about every installed version. If a product supports Excel and Calc, record and test their paths separately. The shared CSV extension does not establish shared behavior. Treat a changed application locale or a format conversion as a change to the supported consumption environment.

Prefix workarounds spend a data-fidelity budget

An apostrophe or control-character prefix may prevent interpretation along a particular path, but it also changes the field. A machine might retain that prefix as part of an identifier. A later cleanup step might remove it and restore the original interpretation risk. OWASP warns about limitations of prefix-based approaches and save/reopen behavior; it does not offer a universal sanitizer.

Our recommendation is to make any such transformation an approved, recorded rule with end-to-end tests. Preserve original values in an appropriately restricted location, not necessarily in the exported file. Recipients should not need to guess which spaces or prefixes to strip to recover a valid customer identifier.

Counting “sanitized cells” alone is misleading. Do the exported values still refer to the same customer, order and note? A transformation that prevents interpretation while corrupting identifiers has not made the report operationally reliable. Measure literal round-trip fidelity alongside the absence of unexpected formulas.

Give approved formulas a separate creation path

If the report genuinely needs workbook calculations, reviewed application templates should create them. Model-provided values can become validated inputs, not formula source text. Concatenating untrusted strings into a formula would reopen the boundary, even if the surrounding template had been approved.

ZharfAI proposes an explicit inventory of formula cells and their expected templates. Every other cell is data-only. For a report that needs no workbook calculations, zero formulas is a simpler expectation. If a model proposes a formula, retain it as text for review; activating it is a separate action with separate authority.

Most readers need a result, not an executable calculation. Compute approved results upstream when that meets the use case, and include enough provenance to explain them. Do not silently replace a promised recalculating workbook with fixed numbers; the choice is part of the export's declared behavior.

Cell semantics also do not settle confidentiality. Perfectly inert text may belong to another customer. Our output-release authorization guide explains why permission to read differs from permission to distribute. A safe string representation is not permission to send the report to any recipient.

Build a harmless fixture that catches semantic changes

Start with =1+1, plus-prefixed text, an at-sign label, a minus-prefixed string and a separately validated negative number. Add a leading-zero identifier, commas, quotes, line breaks, tabs, carriage returns and Persian text. Full-width variants and leading whitespace are useful probes for multilingual consumption paths. The aim is to observe typing and fidelity, not to execute an attack.

Define the expected result before generating the artifact. A note remains exactly the same string. An approved numeric value remains numeric. An out-of-contract value is rejected. Include empty and oversized inputs so the product cannot quietly adopt a truncation or omission policy while passing the happy path.

For XLSX, inspect the generated XML package and assert that untrusted-data cells contain no formula nodes. Check recovered string values, row counts and the absence of unwanted automatic hyperlinks. For a template with approved formulas, compare their locations and expressions against the inventory rather than accepting any formula merely because some are expected.

A package inspection does not establish every application's behavior. Product acceptance should also import, save and reopen the fixture using each supported version and setting. Include conversion to CSV if recipients actually do it. Use synthetic values so the test does not disclose real records. A preview image cannot prove a cell's underlying type.

Make the release decision and its limits visible

Accept an export path when its column contract is explicit, untrusted fields remain literal, approved formulas are isolated and the supported consumption path preserves the promised values. If the only available CSV path cannot meet those conditions, change the delivery method or state the narrower use; do not hide the limitation behind “escaped.”

Record unexpected-formula counts, string mismatches after round trips, missing rows, truncation and rejected-input reasons. A spike in rejections may indicate a changed business field rather than an attack. Keep sensitive values out of routine logs; record the rule and enough controlled evidence to investigate.

Rerun the fixture after writer-library upgrades, import-setting changes, new locales or format changes. Assign an owner to the supported-consumer list. “Works in a spreadsheet” is too vague to remain a dependable contract as recipients change tools.

The useful promise is not that the model never emits an equals sign. It is that the system knows whether a field is data or a permitted calculation, preserves that distinction through the declared path, and detects when a transformation breaks it.

Source notes — reviewed September 18, 2026

Documented tool behavior comes from the sources below. The decision table, column contract, sample code and acceptance criteria are ZharfAI engineering proposals, not a comprehensive Excel security test or an incident report. Structural file inspection and testing an application that opens the file are different forms of evidence.

#AI Output Security#Spreadsheets#Formula Injection#CSV Exports#Data Quality

Related Posts

Name one process for a discovery call

If this note maps to a real system in your organisation, start with the services page or a shipped case study.