CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-125116

CVE-2026-125116: Type Confusion in Mongoose Discriminator Resolution

Alon Barad
Alon Barad
Software Engineer

Nov 10, 2026·11 min read·2 visits

Executive Summary (TL;DR)

Mongoose prior to versions 6.13.12, 7.8.13, 8.24.7, and 9.11.4 fails to check whether a discriminator key is an own property on discriminator registry objects. Attackers supplying `__t: 'constructor'` can bypass schema strictness and validation in specific write operations or trigger unhandled TypeErrors during document instantiation and query hydration.

CVE-2026-125116 (GHSA-wr5m-5jph-8m96) is a type confusion vulnerability (CWE-843) in Mongoose, the MongoDB object modeling library for Node.js. When resolving discriminator models or schemas via user-supplied discriminator keys (defaulting to `__t`), Mongoose performs direct property indexing on plain JavaScript registry objects without verifying own-property ownership. Supplying inherited `Object.prototype` property names such as `'constructor'` causes Mongoose to resolve built-in functions rather than valid Mongoose constructors, resulting in unhandled runtime exceptions, schema validation bypasses, and persistent collection query denial of service.

Vulnerability Overview

Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js that manages relationships between data, provides schema validation, and translates between objects in code and the representation of those objects in MongoDB. A core feature of Mongoose is discriminators, which provide a schema inheritance mechanism. Discriminators allow multiple models with overlapping schemas to be stored within the same underlying MongoDB collection, differentiated by a specific field known as the discriminator key (which defaults to __t).

In versions prior to 6.13.12, 7.8.13, 8.24.7, and 9.11.4, Mongoose stores registered discriminators in standard JavaScript objects ({}), such as Model.discriminators and schema.discriminators. When Mongoose processes documents during instantiation, querying, updating, or population, it inspects the document's discriminator key and looks up the corresponding model or schema by directly indexing the registry object.

Because standard JavaScript objects inherit properties and methods from Object.prototype, direct property lookups without own-property checks will resolve inherited properties such as constructor, toString, valueOf, and hasOwnProperty. This flaw is classified under CWE-843 (Access of Resource Using Incompatible Type / Type Confusion).

When an application passes untrusted input containing a discriminator key set to an inherited property name, Mongoose retrieves a native JavaScript function from Object.prototype instead of a valid Mongoose discriminator model or schema. Depending on the specific property name and execution path, this type confusion leads to unhandled TypeError crashes, bypass of schema casting and strict field filtering, or persistent poisoning of the MongoDB collection.

Root Cause Analysis

The root cause of CVE-2026-125116 is the use of plain JavaScript object literals with standard prototype chains as lookup dictionaries, combined with unguarded bracket notation indexing (registry[key]). In JavaScript, any object created via {} or new Object() has Object.prototype as its prototype. Consequently, evaluating obj['constructor'] returns [Function: Object], and evaluating obj['toString'] returns [Function: toString].

Across the Mongoose codebase, multiple internal functions check if a model or schema has discriminators configured and then immediately resolve the target discriminator using the value extracted from the user-supplied document or query filter. Because the resolved functions on Object.prototype are truthy values in JavaScript, conditional checks verifying whether the discriminator exists pass without error.

The behavior splits into two primary failure modes depending on which Object.prototype property is referenced. If the attacker supplies a non-constructor method such as __t: 'toString' or __t: 'hasOwnProperty', Mongoose attempts to either invoke it with the new operator (new Discriminator(doc)) or access Mongoose-specific properties on it (such as discriminator.schema.eachPath()). Because Object.prototype.toString is not a constructor and lacks a .schema property, the Node.js runtime immediately throws an unhandled TypeError.

If the attacker supplies __t: 'constructor', the lookup resolves to the built-in Object constructor ([Function: Object]). When Mongoose executes new Discriminator(doc, fields, skipId), it actually executes new Object(doc, fields, skipId). According to the ECMAScript specification, when new Object(value) is called with an argument that is already an object, it returns the argument object unchanged. Instead of returning a hydrated mongoose.Document instance equipped with validation hooks, internal state tracking ($__), and schema type casting, the constructor returns the raw, unvalidated user input object verbatim.

This unguarded lookup pattern was replicated across six distinct functional areas in Mongoose:

  • Model Compilation and Instantiation (lib/model.js): Direct indexing of model.discriminators[doc[discriminatorKey]] during new Model(doc), Model.create(), and Model.insertOne().
  • Query Result Hydration (lib/queryHelpers.js): Direct indexing in createModel() when hydrating raw MongoDB documents returned by Model.find() or Model.findOne().
  • Query and Update Casting (lib/cast.js, lib/query.js, lib/helpers/query/castUpdate.js): Indexing schema.discriminators when casting filter conditions or update payloads.
  • Document and Embedded Arrays (lib/schema/array.js, lib/schema/documentArray.js, lib/types/documentArray/methods/index.js): Resolving subdocument discriminators during .push() or .create() on embedded arrays.
  • Population (lib/helpers/populate/getModelsMapForPopulate.js): Resolving schematype.caster.discriminators during reference population.

> [!NOTE] > While this vulnerability involves Object.prototype properties, it is strictly a read-side prototype lookup flaw resulting in type confusion. It does not modify or pollute Object.prototype and is not a prototype pollution vulnerability.

Code Analysis

To remediate the vulnerability across all affected code paths, the Mongoose maintainers introduced a centralized helper function, getDiscriminatorByKey, in lib/helpers/discriminator/getDiscriminatorByKey.js. This function verifies that the requested key is a direct own property of the discriminators object before returning the value.

'use strict';
 
/**
 * Returns the discriminator registered under `key`, ignoring inherited properties
 * like `constructor` or `toString`, because `key` may come from user data.
 *
 * @param {object} discriminators
 * @param {string} key
 * @api private
 */
 
module.exports = function getDiscriminatorByKey(discriminators, key) {
  if (discriminators == null || key == null) {
    return null;
  }
  // Ensures inherited properties on Object.prototype return null
  return Object.hasOwn(discriminators, key) ? discriminators[key] : null;
};

In the 8.x and 9.x release branches, the helper uses Object.hasOwn(discriminators, key). In the backported fixes for the 6.x and 7.x release branches, the helper uses Object.prototype.hasOwnProperty.call(discriminators, key) to maintain compatibility with older Node.js runtimes.

In lib/model.js, the Model.compile function previously resolved discriminators during model instantiation via direct bracket notation. The patch replaces this with a call to getDiscriminatorByKey:

@@ -5070,7 +5071,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
       }
 
       // If discriminator key is set, use the discriminator instead (gh-7586)
-      const Discriminator = model.discriminators[doc[discriminatorKey]] ||
+      const Discriminator = getDiscriminatorByKey(model.discriminators, doc[discriminatorKey]) ||
         getDiscriminatorByValue(model.discriminators, doc[discriminatorKey]);
       if (Discriminator != null) {
         return new Discriminator(doc, fields, skipId);

Similarly, in lib/helpers/query/castUpdate.js, when Mongoose casts an update operation on a model with discriminators, it inspects the query filter for the discriminator key. Prior to the fix, supplying { __t: 'constructor' } in the filter caused schema to be overwritten with [Function: Object], breaking update casting:

@@ -71,7 +72,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
       schema.discriminators != null) {
     const discriminatorValue = filter[schema.options.discriminatorKey];
     const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
-    schema = schema.discriminators[discriminatorValue] ||
+    schema = getDiscriminatorByKey(schema.discriminators, discriminatorValue) ||
       byValue?.schema ||
       schema;

In lib/queryHelpers.js, the createModel function is responsible for instantiating Mongoose documents from raw BSON objects returned by the MongoDB driver during read queries. The patch secures this hydration path against poisoned documents stored in the database:

@@ -98,7 +99,7 @@ exports.createModel = function createModel(model, doc, fields, userProvidedField
 
   const value = doc[key];
   if (key && value && model.discriminators) {
-    const discriminator = model.discriminators[value] || getDiscriminatorByValue(model.discriminators, value);
+    const discriminator = getDiscriminatorByKey(model.discriminators, value) || getDiscriminatorByValue(model.discriminators, value);
     if (discriminator) {
       const _fields = clone(userProvidedFields);
       exports.applyPaths(_fields, discriminator.schema);

The fix is comprehensive across the library's discriminator lookup points. By enforcing Object.hasOwn (or hasOwnProperty) inside getDiscriminatorByKey and auditing all references to .discriminators[, the patch prevents fallback to Object.prototype regardless of which property name is supplied in user input.

Exploitation

Exploiting CVE-2026-125116 requires an application to use Mongoose models configured with at least one .discriminator(), and to pass user-controlled input containing the discriminator key (by default __t) into Mongoose model, query, or array methods. No authentication is required at the library level, though network exploitation depends on how the target application exposes endpoints that accept JSON input.

Scenario 1: Document Instantiation Type Confusion

When an application instantiates a Mongoose model using new Model(req.body), passing __t: 'constructor' causes the new operator to return the raw input object rather than a mongoose.Document instance.

const mongoose = require('mongoose');
 
const Base = mongoose.model('Base', new mongoose.Schema({ 
  name: String, 
  age: Number 
}));
Base.discriminator('Child', new mongoose.Schema({ 
  extra: String 
}));
 
const payload = { 
  name: 'attacker', 
  __t: 'constructor' 
};
 
const doc = new Base(payload);
 
// doc is the raw input object, not a Mongoose Document
console.log(doc instanceof mongoose.Document); // false
console.log(doc === payload);                  // true

When the application subsequently attempts to call standard Mongoose document methods such as await doc.save() or await doc.validate(), Node.js throws TypeError: doc.save is not a function, crashing the request handler.

Scenario 2: Schema Validation Bypass and Persistent Collection Poisoning

A more severe exploitation path occurs when an application uses Model.bulkWrite() with the { skipValidation: true } option. During bulkWrite processing for insertOne operations, Mongoose instantiates the model to cast values to their schema types and strip undeclared fields (enforcing strict: true).

Because new Base(doc) returns the raw doc unmodified when __t: 'constructor' is present, Mongoose skips both type casting and strict field stripping. When skipValidation: true is active, Mongoose does not attempt to invoke validation methods on the resulting object and passes the raw object directly to the underlying MongoDB driver for insertion.

const mongoose = require('mongoose');
 
async function exploit() {
  await mongoose.connect('mongodb://localhost:27017/test_db');
 
  const BaseSchema = new mongoose.Schema({
    name: String,
    age: Number
  }, { strict: true });
 
  const Base = mongoose.model('Base', BaseSchema);
  Base.discriminator('Child', new mongoose.Schema({ extra: String }));
 
  // Step 1: Bypass strict mode and type casting via bulkWrite
  await Base.bulkWrite([{
    insertOne: {
      document: {
        name: 'victim_record',
        age: 'not_a_number',         // Bypasses Number casting
        isAdmin: true,               // Bypasses strict: true filtering
        internalToken: 'secret123',  // Arbitrary field injection
        __t: 'constructor'
      }
    }
  }], { skipValidation: true });
 
  // Step 2: Persistent Query Denial of Service
  // Any subsequent query hydrating this document crashes
  await Base.find();
  // Throws: TypeError: Cannot read properties of undefined (reading 'eachPath')
}

Once this document is persisted in MongoDB with __t: 'constructor', the collection is poisoned. Whenever any user or background process executes a read query (such as Base.find() or Base.findOne()) that matches the poisoned record, Mongoose attempts to hydrate the document via createModel(). In createModel(), model.discriminators['constructor'] resolves to Object, and Mongoose attempts to call exports.applyPaths(_fields, discriminator.schema). Because Object.schema is undefined, applyPaths crashes trying to read schema.eachPath, rendering the collection unreadable through Mongoose until the offending record is manually deleted using the raw MongoDB driver.

Impact Assessment

CVE-2026-125116 is rated at a CVSS v3.1 base score of 4.8 (Medium) with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L. The Attack Complexity is rated as High (AC:H) because exploitation requires the target Mongoose model to have discriminators configured, and achieving schema bypass requires specific operational patterns such as bulkWrite with skipValidation: true or raw document insertion.

The integrity impact (I:L) stems from the bypass of Mongoose's schema enforcement. Applications rely on Mongoose schemas with strict: true (the default setting) to act as an allowlist filter, stripping unexpected properties from user input before database persistence, and casting primitive types (such as converting strings to numbers or booleans). By supplying __t: 'constructor' in vulnerable write flows, an attacker can inject arbitrary uncast fields (such as privilege flags like role or isAdmin) directly into the MongoDB collection.

The availability impact (A:L) manifests in two ways. First, single-request denial of service occurs when unhandled TypeError exceptions are thrown during model instantiation, array .push() operations, or query casting. In Node.js applications without proper error-handling middleware or process supervision, an unhandled promise rejection or uncaught exception will terminate the Node.js process.

Second, if a document containing __t: 'constructor' (or another Object.prototype property name) is written to the database, it causes a persistent denial of service for all Mongoose queries reading that document. Standard read operations across the application will repeatedly fail with TypeError: Cannot read properties of undefined (reading 'eachPath'). As of current threat intelligence data, the EPSS score is 0.00339 (27.55th percentile), and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

Remediation

The primary remediation is to upgrade the mongoose npm package to a patched release that incorporates the getDiscriminatorByKey own-property check. Maintainers have released patched versions across all active major release trains:

  • Mongoose 9.x: Upgrade to 9.11.4 or later.
  • Mongoose 8.x: Upgrade to 8.24.7 or later.
  • Mongoose 7.x: Upgrade to 7.8.13 or later.
  • Mongoose 6.x: Upgrade to 6.13.12 or later.

For environments where an immediate dependency upgrade cannot be deployed, security teams should implement input validation middleware to inspect incoming request bodies and query parameters. Specifically, applications should strip or reject any discriminator key field (default __t, or any custom key defined via schema.options.discriminatorKey) if its value matches a property on Object.prototype or is not an explicitly expected discriminator name.

// Express middleware workaround to sanitize discriminator keys
const ALLOWED_DISCRIMINATORS = new Set(['ChildModelA', 'ChildModelB']);
 
function sanitizeDiscriminatorKey(obj, key = '__t') {
  if (obj && typeof obj === 'object') {
    if (key in obj && !ALLOWED_DISCRIMINATORS.has(obj[key])) {
      delete obj[key];
    }
    for (const k of Object.keys(obj)) {
      if (typeof obj[k] === 'object') {
        sanitizeDiscriminatorKey(obj[k], key);
      }
    }
  }
}

Additionally, developers should audit their codebase for uses of Model.bulkWrite() where { skipValidation: true } is enabled, ensuring that user-controlled payloads are never passed directly into insertOne or updateOne descriptors without prior schema validation.

If an application is already experiencing persistent query crashes due to poisoned documents in MongoDB, administrators must connect using mongosh or the native MongoDB driver (bypassing Mongoose hydration) to locate and remove the corrupted records:

// Execute in mongosh to remove poisoned records
db.collection_name.deleteMany({
  __t: { 
    $in: [
      "constructor", 
      "toString", 
      "valueOf", 
      "hasOwnProperty", 
      "isPrototypeOf", 
      "propertyIsEnumerable", 
      "toLocaleString",
      "__proto__"
    ] 
  }
});

Official Patches

Automattic (Mongoose)Mongoose 9.11.4 Release
Automattic (Mongoose)Mongoose 8.24.7 Release
Automattic (Mongoose)Mongoose 7.8.13 Release
Automattic (Mongoose)Mongoose 6.13.12 Release

Fix Analysis (6)

Technical Appendix

CVSS Score
4.8/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L
EPSS Probability
0.34%
Top 72% most exploited

Affected Systems

Mongoose (npm package `mongoose`)

Affected Versions Detail

Product
Affected Versions
Fixed Version
mongoose
Automattic
< 6.13.126.13.12
mongoose
Automattic
>= 7.0.0, < 7.8.137.8.13
mongoose
Automattic
>= 8.0.0, < 8.24.78.24.7
mongoose
Automattic
>= 9.0.0, < 9.11.49.11.4
AttributeDetail
CVE / Advisory IDCVE-2026-125116 / GHSA-wr5m-5jph-8m96
Weakness ClassCWE-843: Access of Resource Using Incompatible Type ('Type Confusion')
CVSS v3.1 Score4.8 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L)
EPSS Score0.34% (27.55th Percentile)
Attack VectorNetwork (Untrusted JSON input controlling Mongoose discriminator keys)
ImpactSchema Validation & Strictness Bypass, Request DoS, Persistent Query DoS
Exploit StatusPublic Proof-of-Concept (PoC) Available
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1499.004Endpoint Denial of Service: Application or System Exploitation
Impact
T1565.001Data Manipulation: Stored Data Manipulation
Impact
CWE-843
Access of Resource Using Incompatible Type ('Type Confusion')

The software allocates or initializes a resource such as a pointer, object, or variable using one type, but it later accesses that resource using a type that is incompatible with the original type.

Known Exploits & Detection

GitHub Security AdvisoryOfficial GitHub Security Advisory containing proof-of-concept code demonstrating type confusion via `__t: 'constructor'` and persistent collection poisoning via `bulkWrite`.

Vulnerability Timeline

Fix commits authored and pushed to Mongoose repository across v6.x, v7.x, v8.x, and v9.x branches
2026-10-23
CVE-2026-125116 published to CVE.org and NIST NVD
2026-11-09
GitHub Security Advisory GHSA-wr5m-5jph-8m96 published
2026-11-10

References & Sources

  • [1]GitHub Security Advisory GHSA-wr5m-5jph-8m96
  • [2]NIST NVD Entry for CVE-2026-125116
  • [3]CVE.org Record for CVE-2026-125116
  • [4]Mongoose Fix Commit 0ecd8040d9b446f36535d79938c130c800f91766
  • [5]Mongoose Fix Commit 18afab75bea861f625b7c5b54635c84567ec566c
  • [6]Mongoose Release 9.11.4
  • [7]Mongoose Release 8.24.7
  • [8]Mongoose Release 7.8.13
  • [9]Mongoose Release 6.13.12

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 2 hours ago•CVE-2026-125119
7.5

CVE-2026-125119: Connection-Level Filter Sanitization Bypass in Mongoose ODM

A flaw in Mongoose's query condition casting pipeline causes the `sanitizeFilter` configuration option to be silently ignored when defined at the connection level via `mongoose.connect()` or `mongoose.createConnection()`. Because internal query methods inspect `Connection.options` rather than `Connection.config`, applications relying on connection-scoped filter sanitization remain vulnerable to NoSQL query selector injection (CWE-943), permitting authentication bypass and unauthorized data access across Mongoose versions 6.x through 9.x.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 3 hours ago•CVE-2026-125110
5.3

CVE-2026-125110: Path Canonicalization Mismatch and Security Header Bypass in Rack::Static

CVE-2026-125110 is a path canonicalization mismatch vulnerability in Rack (specifically within the Rack::Static middleware component). When serving static files, Rack normalizes the requested URL path to resolve the physical file on disk, but evaluates configured path-specific header rules against an unnormalized, raw path that has only undergone URL percent-decoding. Unauthenticated remote attackers can exploit this discrepancy by injecting raw or percent-encoded dot-segments into HTTP requests, causing Rack to serve restricted static assets without their intended security headers.

Amit Schendel
Amit Schendel
5 views•10 min read
•about 4 hours ago•CVE-2026-118776
3.7

CVE-2026-118776: Improper PKCS#7 Padding Validation in node-forge CBC and ECB Cipher Modes

CVE-2026-118776 (also tracked as GHSA-2vgq-wchc-25w7) is an improper input and integrity check validation vulnerability affecting the node-forge cryptographic library prior to version 1.4.1. In vulnerable versions, the PKCS#7 unpadding implementations for Cipher Block Chaining (CBC) and Electronic Codebook (ECB) modes only examined the final byte of the decrypted buffer and permitted padding counts up to four times the cipher block size. This defect allowed malformed ciphertexts containing zero-length padding, oversized padding values, or mismatched preceding padding bytes to pass validation, resulting in silent plaintext truncation of up to four blocks and integrity verification bypass in applications relying on unpadding success.

Amit Schendel
Amit Schendel
2 views•10 min read
•about 5 hours ago•CVE-2026-118774
3.7

CVE-2026-118774: Improper Verification of Cryptographic Signature in node-forge X.509 Certificate Validation

CVE-2026-118774 (GHSA-9wg5-mj3p-v49q) is an improper cryptographic signature verification vulnerability (CWE-347) in node-forge versions prior to 1.4.1. When verifying an X.509 subordinate certificate via certificate.verify(child) or verifyCertificateChain(), the library erroneously selects the RSA padding scheme (e.g., PKCS#1 v1.5 vs. RSASSA-PSS) and RSASSA-PSS parameters from the issuer certificate rather than from the child certificate being verified. This enables an attacker to relabel a PKCS#1 v1.5-signed certificate as an RSASSA-PSS certificate without invalidating the signature check, bypassing downstream security policies that mandate RSASSA-PSS.

Amit Schendel
Amit Schendel
3 views•12 min read
•about 6 hours ago•CVE-2026-118670
8.8

CVE-2026-118670: DOM-Based Cross-Site Scripting in OHIF Viewers dicom-pdf Extension

CVE-2026-118670 (GHSA-xwgp-w3pj-q5h3) is a high-severity DOM-based Cross-Site Scripting (XSS) vulnerability in OHIF Viewers affecting the dicom-pdf extension module. When processing DICOM Encapsulated Document objects, the viewer extracts the untrusted MIMETypeOfEncapsulatedDocument attribute (tag 0042,0012) and uses it directly to instantiate an in-memory Blob. This Blob is then converted to a same-origin Object URL and embedded into the document via an HTML <object> element. Because browsers prioritize the resource's underlying MIME type over the <object> element's type attribute, an attacker who supplies a crafted DICOM file with a MIME type such as text/html can execute arbitrary JavaScript within the application's origin, compromising session tokens, local storage, and Patient Health Information (PHI).

Alon Barad
Alon Barad
3 views•9 min read
•about 7 hours ago•CVE-2026-103022
5.3

CVE-2026-103022: Denial of Service via Unhandled Unicode Exception and File Descriptor Leak in Urwid Web Display

A Denial of Service (DoS) vulnerability exists in the web display module (urwid/display/web.py) of the Urwid console user interface library for Python in versions prior to 4.0.7. The handle_short_request() function unconditionally encodes HTTP POST input as ASCII without exception handling and opens a FIFO pipe file descriptor without a guaranteed cleanup block. Submitting non-ASCII characters triggers an unhandled UnicodeEncodeError that terminates CGI request processing and leaks the open file descriptor. Additionally, the screen update polling routine decodes Unix domain socket streams iteratively as UTF-8 without exception handling or deterministic socket closure, enabling uncaught UnicodeDecodeError exceptions and socket leaks.

Alon Barad
Alon Barad
3 views•10 min read