Does the Export Open Anywhere Else? A Proposed Axis for Data-Export Correctness (September 2026)
Every export is checked by the one reader whose settings match the writer's. A pre-registered seven-signal axis for whether a generated application's export survives arriving anywhere else.
Updated on September 15, 2026
On this page
Quick answer. Every export a developer checks is opened by the person who wrote it, in their own spreadsheet application, on their own machine, with their own small test dataset. That is the one reader whose settings are guaranteed to match the writer's. This axis proposes a way to score whether a generated application's export survives arriving anywhere else. It is a pre-registration, not a result: no builder is scored, named or assigned a posture on this page.
Exporting data looks like the most boring feature a generated application can have. You run a query, you join the values with commas, you set a download header, and the file opens. It is roughly six lines of code and there is nothing in it that looks like a decision.
There are at least six decisions in it, and the format's own standard declines to make any of them for you.
Why this is not already covered
Three axes in this series come close enough that the boundary has to be drawn explicitly, in both directions, or the axis is not worth proposing. Two more are near enough to name.
Against money-arithmetic correctness
Our money-arithmetic correctness axis scores whether an amount stays exact from column to response body. It is the nearest neighbour, and the boundary is drawn by that axis itself, in its own scope note: "It does not score the display layer's design. Whether a currency symbol sits before or after the number, and whether the locale is right, is a formatting question and belongs to internationalization rather than here."
That is correct, and it leaves a gap that internationalization does not fill either, because the i18n axis scores how the application renders text to its own reader. Neither one covers the case where the application writes a file and a different program, configured by a different person, parses it.
The two scores move in opposite directions and both directions are real. An application can hold every amount in an exact type, compute flawlessly, pass money arithmetic at the top of the scale, and write 1234.56 into a file that a spreadsheet configured for a comma decimal separator does not read as a number at all. An application can do binary floating-point arithmetic throughout, fail money arithmetic completely, and still produce a file that every downstream reader parses exactly as intended, because the defect is in the value and not in the handoff.
Against text-comparison and collation correctness
Our text-comparison and collation axis scores whether two strings the system holds are treated as the same value. This axis scores whether a string the system holds arrives intact in a program the system does not control.
The boundary is sharp in both directions. A string can survive the handoff byte for byte and change meaning on arrival, which is the whole of formula injection. A string can be transformed on the way out, deliberately and correctly, and still be the same value to its reader.
The two axes also interact in a way that is worth a section of its own, below, because one axis's recommended remedy can create the other axis's defect.
Against outbound-call failure
Our outbound-call failure axis scores what a generated application does when a third party it depends on is slow, rate limited or silent. These two axes do not overlap. They compose, which is a different and more useful relationship.
An export assembled from rows that each require an outbound call is the place where that axis's failure mode becomes invisible. A call that never resolves, inside a handler with no deadline, produces a file that stops early. The file is still syntactically perfect. Every row in it is correct. Nothing in the format records how many rows there were meant to be, so a short export and a complete export are the same kind of object. The symptom appears in this axis and the cause lives in that one, which is why signal 6 below exists at all.
Named without a link, to stay inside the internal-link budget
Our internationalization axis scores locale-aware formatting in the interface the application renders. Our file-upload and media-handling axis scores bytes arriving from an untrusted source. This axis is the inverse direction of the second: bytes leaving toward a trusted recipient, who will open them in a program that treats some of those bytes as instructions.
Four documented facts that make this measurable
1. The format's own standard says there is no standard
RFC 4180 is the document everyone cites for CSV. It is worth reading what it says about its own authority.
RFC 4180, section 2, verbatim: "While there are various specifications and implementations for the CSV format, there is no formal specification in existence, which allows for a wide variety of interpretations of CSV files. This section documents the format that seems to be followed by most implementations."
The memo's own status line is equally direct: "It does not specify an Internet standard of any kind." The document is Informational. It describes a convention rather than prescribing one, and it says so twice on the first two pages.
This matters for a benchmark because it means conformance is not a binary a rubric can check. The seven numbered rules in section 2 are worth following, and rule 6 is phrased as advice rather than obligation: "Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes." Should, not must.
There is one further detail that is easy to miss. The memo's Security Considerations section, in full, reads: "See discussion above in section 3." Section 3 is the MIME type registration. The format standard has no security model of its own, which is unremarkable for 2005 and directly relevant to fact 4.
2. The published grammar cannot express a name with an accent in it
We recomputed this rather than quoting it, because the consequence is easy to state and easy to get wrong.
RFC 4180 publishes an ABNF grammar. Its terminal is TEXTDATA = %x20-21 / %x23-2B / %x2D-7E. Expanding those three ranges gives 93 code points. The highest is 0x7E. Working through the grammar: an unquoted field is *TEXTDATA, and a quoted field is DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE, which adds the comma, carriage return, line feed and the doubled quote and nothing else.
So under the published grammar, read literally, no byte above 0x7E is permitted in any field, quoted or unquoted. Ana-Maria is expressible. José is not. Neither is naïve, and neither is any name written in a non-Latin script.
The escape hatch is the MIME registration, and it is optional. RFC 4180, section 3, verbatim: "Common usage of CSV is US-ASCII, but other character sets defined by IANA for the 'text' tree may be used in conjunction with the 'charset' parameter." The same registration makes the header row optional too, and adds: "Implementors choosing not to use this parameter must make their own decisions as to whether the header line is present or absent."
An application that serves text/csv with no charset parameter has therefore declared, by omission, that its file is US-ASCII. If the bytes are UTF-8, the receiving program is guessing, and it is guessing about exactly the customer names most likely to be complained about.
3. The delimiter is not in the file. It is in the reader's operating system
The comma in comma-separated values is a default, not a property of the format.
Microsoft's documentation on importing and exporting text files, verbatim: "Comma separated values text files (.csv), in which the comma character (,) typically separates each field of text. You can change the separator character that is used in both delimited and .csv text files."
The instructions for changing it do not live in the application. They route through Windows regional settings, ending at the List separator box in the Customize Format dialog. The same page records a coupling that is the important part for anyone writing an exporter: "If you want to use a semi-colon as the default list separator when you Save As .csv, but need to limit the change to Excel, consider changing the default decimal separator to a comma - this forces Excel to use a semi-colon for the list separator."
Read that in the direction a reader experiences it. Their decimal separator determines their field separator. A file written with comma delimiters and dot decimals is unambiguous for a reader configured one way and is a different document for a reader configured another way, and nothing in the file says which convention it was written under.
That the underlying convention genuinely varies is documented separately. Microsoft's globalization guidance, verbatim: "Two characters frequently used for the decimal separator are the comma (, U+002C) and the dot (. U+002E)", and the guidance adds a detail worth keeping, that the choice "can depend on context. For example, in Switzerland, the comma is used as the decimal separator for most situations, but the dot is used for currencies."
So the convention is not even stable within a single country.
4. The receiving program executes what it opens
The fourth fact is the one that turns an export from a correctness question into a security question.
OWASP, verbatim: "CSV Injection, also known as Formula Injection, occurs when websites embed untrusted input inside CSV files. When a spreadsheet program such as Microsoft Excel or LibreOffice Calc is used to open a CSV, any cells starting with = will be interpreted by the software as a formula."
OWASP enumerates the initiating characters: equals, plus, minus, at, tab (0x09), carriage return (0x0D) and line feed (0x0A). It adds a set most screening code misses, the "Full-width (double-byte) variants of formula-initiating characters such as = , + , - , and @ , which may be interpreted as formulas in some locales (e.g., Japanese environments)."
Note that three of those seven are the same characters RFC 4180's rule 6 says to quote. A field beginning with a line break is simultaneously a structural problem and an injection vector, which is why the two signals below are separate rows rather than one.
OWASP is also unusually candid about how hard this is to fix, and the candour is load-bearing for the rubric. It records that "Microsoft Excel may remove quotes or escape characters from CSV cells when a file is saved and re-opened. As a result, commonly suggested CSV injection mitigations may fail and previously escaped formulas may become active again", and concludes: "There is no universal CSV sanitization strategy that is safe for all spreadsheet applications and all downstream consumers."
A rubric cannot score a remedy that its own primary source says does not exist. It can score whether the application made a decision and recorded it, which is what signal 4 does.
A ten-byte difference, recomputed
The structural half of this axis is small enough to demonstrate exactly, so we did rather than describing it.
We took five rows containing three ordinary hard cases: a value with a comma in it, a value with a double quote in it, and a value with an embedded line break. We serialised them twice, once by joining fields with commas and rows with CRLF, which is the shape hand-written export code takes, and once with a conformant writer. Then we parsed both back.
The conformant file round-trips exactly: five rows in, five rows out, every field identical. It costs 152 bytes against the naive file's 142.
The naive file does not. Five rows in, six rows out. The value Smith, John became two fields, turning a three-field row into a four-field row. The value containing a line break split its record in half, producing two rows of two fields. The per-row field counts of the naive file are 3, 3, 4, 3, 2, 2 against a conformant 3, 3, 3, 3, 3.
The third hard case is the instructive one. The row containing He said "yes" is invalid under RFC 4180 rule 5, which states that where fields are not enclosed in double quotes, double quotes may not appear inside them. Our reader accepted it anyway and returned the value unchanged. The file was malformed and the parser forgave it, which is precisely why a developer's own check passes.
Ten bytes separate a file that round-trips from a file that silently gains a row.
The proposed rubric
Seven signals. Weights are a starting point for community revision, not a settled formula.
Scroll to see more
| Signal | Weight | What a failing case looks like |
|---|---|---|
| Structural escaping of every field | 22 | Fields are joined with a separator and rows with a newline, so any value containing that separator, a double quote or a line break changes the shape of the file rather than its contents |
| Formula-initiator screening, applied after any normalisation | 20 | A value beginning with an initiating character is written through unchanged, so opening the file in a spreadsheet runs it |
| Character encoding declared rather than assumed | 16 | Bytes are UTF-8 and nothing says so: no charset parameter on the media type, no declaration anywhere, so every non-ASCII value depends on the reader guessing correctly |
| Delimiter and decimal convention chosen for a named consumer | 13 | A comma delimiter and a dot decimal are emitted unconditionally, with nothing in the project recording who the file is for or which convention they read |
| Values that must stay text are protected as text | 10 | Identifiers, reference codes and anything with a leading zero are written bare, so the receiving program is free to re-type them |
| A short export is distinguishable from a complete one | 11 | The file has no row count, no completion marker and no manifest, so a truncated export and a full one are the same kind of object to every consumer |
| The export round-trips through a conformant reader | 8 | Nothing in the project has ever parsed the file the application produces, so the only evidence it is well formed is that it opened once, in one program |
Three weighting decisions worth arguing about now
Why structural escaping carries the most. It is the only row whose failure changes the shape of the data rather than its contents. A misparsed number is one wrong cell that a reader may notice. A record that splits in two shifts every subsequent field into the wrong column, and the resulting file is still perfectly valid, still opens, and still looks like a table.
Why screening is almost as heavy, and why its row name includes an ordering. The signal is not "does the code screen for =". It is whether screening happens at the right moment. See the second tension below: a normalisation step that runs after screening can reintroduce exactly what the screening removed, and both steps are individually correct.
Why the round-trip row is the lightest and still on the list. It is the least consequential row and the one most likely to be missing entirely, because it is not a property of the file at all. It is a property of whether anyone ever checked. It sits on the list for the same reason the display-formatting row sits at the bottom of the money-arithmetic rubric: its absence is what conceals the six rows above it.
Four postures
- Level 0, concatenated. Values are joined with a separator. Any value containing that separator, a quote or a newline corrupts the structure. Encoding is whatever the runtime emitted, declared nowhere.
- Level 1, escaped. Fields are quoted and embedded quotes doubled, so the file round-trips structurally. Contents are still passed through untouched, so an initiating character is still an instruction on arrival, and the encoding is still undeclared.
- Level 2, screened and declared. Everything in Level 1, plus initiating characters are handled before the file is written, the encoding is declared on the media type, and the delimiter is a recorded choice rather than a default.
- Level 3, addressed. Everything in Level 2, plus the project records who the export is for, the convention follows from that record, values that must remain text are protected, completeness is detectable by the recipient, and the emitted file is parsed by a conformant reader as part of the build.
The 0 to 1 step is the one worth arguing about. It is unambiguous progress in structure and it is not progress at all in safety: a Level 1 export is more likely to open cleanly, which means it is more likely to be opened, and the formula in it is still live. Level 1 is the first posture that reliably delivers its payload.
The measurement protocol
Nine of these ten steps read static artifacts, which is what makes two runs on the same export agree.
- Generate a fixed reference application from the same prompt suite used for every axis, one generation per builder, no manual edits. The reference feature is a table of customer records with a name, a reference code, an amount and a note, plus an export control, because that is the shortest specification that forces every row in the rubric.
- Export the project the builder allows you to export.
- Locate the export handler in the emitted source and record whether serialisation is hand-written or delegated to a library.
- Record the response headers the handler sets, verbatim, including the media type and any charset parameter.
- Control step. Run the export against the seeded dataset as generated, open the result, and record that it looks correct. This step establishes the baseline that the rest of the protocol is designed to defeat. Agreement here is not evidence of anything.
- Re-seed with the adversarial battery and re-export. The battery is six values: one containing the delimiter, one containing a double quote, one containing a line break, one beginning with an equals sign, one beginning with a full-width equals sign, and one reference code with a leading zero.
- Parse the resulting file with a conformant reader and record the row count and the per-row field count against what was seeded. Report the counts, not a pass.
- Record the byte sequence written for each of the six battery values, and classify each as passed through, quoted, escaped, prefixed or altered.
- Re-read the same file after a save-and-reopen cycle in a spreadsheet application, and record whether any protection applied in step 8 survived. OWASP documents that some do not.
- Documentation control. Record what the project's own README, comments or docs claim about the export, and compare it against steps 6 to 9. A divergence between documented and measured behaviour is a finding in its own right.
The named trap: the my-spreadsheet illusion
Each axis in this series names the illusion that hides its defect. Tests that pass without asserting are the green-check illusion. A surface whose only consumer wrote itself is the sole-consumer illusion. A value that is correct on screen and wrong in the database is the display-rounding illusion.
Here it is the my-spreadsheet illusion, and it is the seventh member of a family this series keeps finding: the defect is invisible because every observation available at the time of building is generated by a single actor.
Opening the file is the test. The test is run by the developer, on the developer's machine, in the developer's spreadsheet application, under the developer's regional settings, against a dataset the developer seeded with names like Test User and amounts like 100. In that configuration, a Level 0 export and a Level 3 export are byte-for-byte indistinguishable in everything the developer can observe, because every code path that separates them requires a value they did not seed, a locale they do not run, or a reader they do not have installed.
The file opens. The columns line up. The screenshot is correct.
It surfaces later, in three places, none of which is the developer's machine: when a customer whose name contains a comma or an accent is exported, when the recipient's spreadsheet is configured for a different decimal separator, and when someone on the finance team opens a file containing a value that another user typed into a support form months earlier.
The third case is the reason this axis is not purely about tidiness. The code runs on the recipient's computer, not on the server, and the recipient is usually a colleague who has every reason to trust a file that came from their own company's application.
Two documented tensions worth stating
The remedy is scoped to one consumer, and the source says so. The mitigation OWASP describes as reliable for spreadsheets is to prefix an offending cell with a tab character inside the quoted field. OWASP immediately records the cost: "The tab character remains part of the underlying data and may affect downstream processing if the CSV is later imported programmatically", and scopes its own advice, noting the mitigation "is best suited for CSV files intended for human viewing in spreadsheet applications." The same is true of the more common remedy of prefixing with an apostrophe, which a spreadsheet hides and a programmatic reader returns as part of the value.
So an export made safe for a person reading it is an export made wrong for a program re-importing it, and the reverse. This is not a defect in either remedy. It is why signal 4 scores whether a consumer is named rather than scoring which convention was chosen, and it is why a rubric row reading "sanitises the output" would be unscoreable against a source that states plainly that no universal strategy exists.
One of our own axes can manufacture this axis's defect, and the hinge is a detail our own rubric leaves unspecified. Our text-comparison and collation axis rewards Unicode normalisation at the boundary at weight 20. It names the act and does not specify the form, which at the time seemed like appropriate neutrality.
The two commonest forms differ on exactly the characters OWASP names. Unicode Annex 15, verbatim: Normalization Form KC is "Compatibility Decomposition, followed by Canonical Composition", and "In the NFKC and NFKD forms, many formatting distinctions are removed."
We recomputed the consequence against Unicode 15.1.0. The full-width equals sign = is U+FF1D. Under NFC it is unchanged. Under NFKC it becomes U+003D, the ASCII equals sign. The same holds for the full-width plus, hyphen-minus and commercial at, which is to say all four of the full-width initiators OWASP lists.
The consequence is concrete. The stored value =1+2 does not begin with an ASCII equals sign. Screen it for formula initiators and it passes, correctly. Normalise it to NFKC afterwards, for the entirely good reason that NFKC is what makes two visually identical names compare equal, and the value written to the file is =1+2, which does.
Neither step is wrong. The ordering is. Screening a string that is not the string you will write is not screening, and the remedy is ordering rather than choice: normalise first, screen second, write third. That an axis of ours can create a defect of ours, through a form its rubric does not name, is a finding about our rubric and we would rather record it than discover it after publishing scores.
What this axis is not
- It is not limited to CSV, and the rubric is currently written as though it were. JSON and spreadsheet-native formats have different failure modes: JSON has a real specification and a real encoding rule, and a spreadsheet-native format carries types rather than guessing at them. Signals 1, 3 and 4 are CSV-shaped as drafted. That is a limitation of this draft rather than of the axis, and it is the first thing we would want a contributor to argue with.
- It is not a scale or performance measure. Whether an export of a million rows completes is a capacity question that belongs to the axes on database connections and outbound calls. Signal 6 is about whether incompleteness is detectable, not about whether it happens.
- It is not a judgement on any builder. No builder is scored, named or assigned a posture on this page, and none will be until the rubric has been through a community-edit window.
- It cannot be fully scored from documentation. Signals 1, 2, 5 and 7 are read from emitted code and emitted files. A builder's marketing page cannot answer them.
- Step 9 is the weakest step and we know it. It requires a spreadsheet application, which makes it the one step in the protocol that is not reproducible from static artifacts alone, and OWASP's own note that behaviour "has been observed in Microsoft Excel and may differ in other spreadsheet applications" means a result there is a statement about one program and one version.
- The weights are a proposal. A reasoned argument that encoding should outrank screening, or that the completeness row is doing work that belongs elsewhere, would change the ranking. We would rather have that argument now than after publishing scores.
Corrections, counter-rubrics and reproduction attempts are welcome. The single most useful thing you can send us is a step 6 result from your own generated application: what you seeded, and what the exported file actually contained.
References
- IETF, RFC 4180, "Common Format and MIME Type for Comma-Separated Values (CSV) Files," October 2005. Section 2 on the absence of a formal specification and the seven-rule description of the format, the ABNF grammar and its
TEXTDATAranges, the section 3 MIME registration with its optionalcharsetandheaderparameters, and the Security Considerations section. Read September 15, 2026: https://www.rfc-editor.org/rfc/rfc4180.txt - OWASP Foundation, "CSV Injection," community attack reference. The definition of formula injection, the list of initiating characters including full-width variants, the note on Excel removing escaping after a save-and-reopen cycle, the tab-prefix mitigation and its downstream-processing trade-off, and the statement that no universal sanitization strategy exists. Read September 15, 2026: https://owasp.org/www-community/attacks/CSV_Injection
- Microsoft, "Import or export text (.txt or .csv) files," Microsoft Support. The comma as a typical rather than required separator, changing the separator, the route through Windows regional settings to the List separator box, and the coupling between the decimal separator and the list separator. Read September 15, 2026: https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba
- Microsoft, "Format numbers," globalization documentation. The comma and dot as the two characters frequently used as decimal separators, and the Switzerland case where the convention depends on whether the value is a currency. Read September 15, 2026: https://learn.microsoft.com/en-us/globalization/locale/number-formatting
- Unicode Consortium, Unicode Standard Annex 15, "Unicode Normalization Forms." Table 1's definition of Normalization Form KC as compatibility decomposition followed by canonical composition, and the statement that many formatting distinctions are removed in the NFKC and NFKD forms. Read September 15, 2026: https://www.unicode.org/reports/tr15/
All recomputations in this article were performed in Python against Unicode 15.1.0 and are reproducible from the values quoted.
Written by
BuilderProof editorial teamCite this benchmark
BuilderProof editorial team. "Does the Export Open Anywhere Else? A Proposed Axis for Data-Export Correctness (September 2026)". BuilderProof, September 2026. https://www.builderproof.org/benchmarks/does-the-export-open-anywhere-else-data-export-axis-september-2026.
@misc{builderproof-does-the-export-open-anywhere-else-data-export-axis-september-2026,
title = {{Does the Export Open Anywhere Else? A Proposed Axis for Data-Export Correctness (September 2026)}},
author = {{BuilderProof editorial team}},
year = {2026},
month = {sep},
howpublished = {\url{https://www.builderproof.org/benchmarks/does-the-export-open-anywhere-else-data-export-axis-september-2026}},
note = {BuilderProof, builderproof.org}
}Frequently asked questions
What does the data-export correctness axis measure?
It is a proposed BuilderProof benchmark axis, drafted 15 September 2026, that scores whether a file a generated application exports is still correct once a program the application does not control opens it. It covers seven signals: structural escaping of every field (22), formula-initiator screening applied after any normalisation (20), character encoding declared rather than assumed (16), delimiter and decimal convention chosen for a named consumer (13), a short export being distinguishable from a complete one (11), values that must stay text being protected as text (10), and the export round-tripping through a conformant reader (8). No builder is scored on this page.
Is CSV not a standard format?
RFC 4180 is Informational and says so about itself. Its section 2 states that 'there is no formal specification in existence, which allows for a wide variety of interpretations of CSV files', and that the document 'documents the format that seems to be followed by most implementations'. Its rules are phrased as advice: fields containing line breaks, double quotes and commas 'should' be enclosed in double-quotes. Its Security Considerations section, in full, is a cross-reference to the MIME registration.
Why does a CSV export open correctly for me and not for the recipient?
Because several of the conventions the file depends on are not in the file. Microsoft documents that the comma 'typically' separates fields and that the separator can be changed through Windows regional settings, and that changing the decimal separator to a comma forces a semi-colon list separator. The encoding is also undeclared by default: RFC 4180 registers an optional charset parameter and notes that 'Common usage of CSV is US-ASCII', so a UTF-8 file served without that parameter leaves the reader guessing.
What is formula injection in an exported file?
OWASP defines CSV Injection as occurring 'when websites embed untrusted input inside CSV files', and notes that when a spreadsheet program opens a CSV, 'any cells starting with = will be interpreted by the software as a formula'. It lists equals, plus, minus, at, tab, carriage return and line feed, plus full-width variants that may be treated as formulas in some locales. OWASP also records that no universal sanitization strategy is safe for all spreadsheet applications and all downstream consumers.
What is the my-spreadsheet illusion?
It is the named trap of this axis. Opening the exported file is the test, and the test is run by the developer, on the developer's machine, in the developer's spreadsheet application, under the developer's regional settings, against data the developer seeded. In that one configuration a careless export and a careful one are indistinguishable, because every code path that separates them requires a value, a locale or a reader the developer does not have.
Related benchmarks
Does the invoice total actually add up? A proposed axis for money arithmetic in AI-generated apps (September 2026)
A proposed BuilderProof axis measuring whether the applications AI app builders generate store and compute money exactly, or only render it that way. Seven weighted signals, four postures, a ten-step protocol with a control step. Pre-registered: no builder is scored here.
Can One Person Sign Up Twice With the Same Email? A Text-Comparison and Collation Axis (September 2026)
Two strings a human reads as one name can be two different byte sequences, and the default comparison in a generated app calls them different. We pre-register a seven-signal rubric for text-comparison and collation correctness, and name the trap that hides it.
Did It Actually Go Through? A Proposed Axis for Outbound-Call Failure (September 2026)
A generated app calls a third party's API from inside a request. We propose an axis for what it does when no answer comes back, and find that retrying is a layered property no single document describes.