Security: CSV header names (toString/constructor/hasOwnProperty) overwrite methods on parsed records
- Dominant language
- TypeScript
- Stars
- 133
- Forks
- 13
- PR merge metrics
- No merged PRs in 30d
Description
## Security: CSV header names (toString/constructor/hasOwnProperty) overwrite methods on parsed records
**Package:** csv42
**Severity:** Medium (Denial of Service / logic corruption in consumers)
**Type:** Special key handling — CSV header names written as object keys without filtering
### Summary
`csv42` converts CSV rows into JSON records using the CSV **header row** as object keys (`record[name] = value`), without filtering special keys. A CSV file with headers like `toString`, `hasOwnProperty`, or `constructor` overwrites those built-in methods on each generated record object with the cell values. Consumers that stringify records (template interpolation, logging) or call `hasOwnProperty` (checks) crash.
The attacker controls the input **directly via CSV file** — this is a common path for user-uploaded CSV parsing.
### Location
`lib/esm/fields.js:15` (and compiled copies):
```js
setValue: path.length === 0 || !nested
? (record, value) => record[name] = value // ← unfiltered header name
: ...
```
### Proof of concept
```js
const { csv2json } = require('csv42')
const records = csv2json('toString,hasOwnProperty\nEVIL,nope\n')
console.log(records[0]) // { toString: 'EVIL', hasOwnProperty: 'nope' }
console.log(typeof records[0].toString) // "string" — was "function"
// Consumer crash:
// records[0].hasOwnProperty('x') → TypeError: records[0].hasOwnProperty is not a function
// `'record: ' + records[0]` → TypeError: Cannot convert object to primitive value
```
### Impact
- **DoS / logic corruption**: user-uploaded CSV with special header names breaks downstream record processing (stringification, property checks).
- No RCE: `__proto__` header does not trigger global prototype pollution (JS language rejects non-object values; also verified parser behavior).
### Suggested fix
In `fields.js` (and `toUniqueNames`), filter or prefix dangerous header names:
```js
const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype', 'toString', 'valueOf', 'hasOwnProperty']);
// skip or rename headers in DANGEROUS_KEYS
```
### Related
Same class of issue confirmed in:
- `@gulujs/toml` — issue #2
- `markty-toml` — issue #16
- `merge-options` — issue #29
- `ini-simple-parser` — issue #1
- `nanoquery` — issue #6
- `dotenv-parse-variables` — process.env global pollution (High, issue #28)
Systemic gap across small CSV/TOML/INI/query-string/merge/env parsers: special keys are rarely filtered when building result objects.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at lib/esm/fields.js:15 and trace setValue and toUniqueNames through the compiled copies. Run the provided csv2json proof of concept, then verify the chosen handling for dangerous headers across the parsing paths. Done means parsed records no longer overwrite built-in methods, with regression coverage for the reported headers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- data, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100