- Operating System: macOS 15.7.3 (Darwin 24.6.0)
- Node Version: 24.16.0
- NPM Version: 11.13.0
- csv-parser Version: 3.2.1
Expected Behavior
When using the raw: true option, rows should be parsed into objects keyed by the CSV headers, with Buffer values — as in 3.2.0 and earlier:
headers: [ <Buffer 61>, <Buffer 62> ]
row: { a: <Buffer 31>, b: <Buffer 32> }
row: { a: <Buffer 33>, b: <Buffer 34> }
Actual Behavior
Since 3.2.1, every header is mapped to null and every row comes back as an empty object — all columns are silently dropped:
headers: [ null, null ]
row: {}
row: {}
Cause: the prototype pollution fix from #250 added sanitizeHeader(), whose first check is if (typeof header !== 'string') return null. With raw: true, parseValue() returns Buffers for every cell — including the header row — so every header fails the type check, becomes null, and is treated as a "skip this column" marker by writeRow(). The same regression hits any custom mapHeaders that returns a non-string value.
The dangerous-key check (__proto__, constructor, prototype) doesn't require rejecting non-strings outright — e.g. Buffer headers could be compared via their string form instead of being discarded.
How Do We Reproduce?
const csv = require('csv-parser')
const { Readable } = require('stream')
Readable.from('a,b\n1,2\n3,4\n')
.pipe(csv({ raw: true }))
.on('headers', (h) => console.log('headers:', h))
.on('data', (row) => console.log('row:', row))
Run with csv-parser@3.2.1 → headers: [ null, null ], all rows {}.
Run with csv-parser@3.2.0 → headers and rows populated as expected.
Expected Behavior
When using the
raw: trueoption, rows should be parsed into objects keyed by the CSV headers, with Buffer values — as in 3.2.0 and earlier:Actual Behavior
Since 3.2.1, every header is mapped to
nulland every row comes back as an empty object — all columns are silently dropped:Cause: the prototype pollution fix from #250 added
sanitizeHeader(), whose first check isif (typeof header !== 'string') return null. Withraw: true,parseValue()returns Buffers for every cell — including the header row — so every header fails the type check, becomesnull, and is treated as a "skip this column" marker bywriteRow(). The same regression hits any custommapHeadersthat returns a non-string value.The dangerous-key check (
__proto__,constructor,prototype) doesn't require rejecting non-strings outright — e.g. Buffer headers could be compared via their string form instead of being discarded.How Do We Reproduce?
Run with
csv-parser@3.2.1→headers: [ null, null ], all rows{}.Run with
csv-parser@3.2.0→ headers and rows populated as expected.