josdejong / josdejong/csv42

Security: CSV header names (toString/constructor/hasOwnProperty) overwrite methods on parsed records

Open
#7 1 comment 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.