Version in base suite: 2.0.0-1 Base version: php-mongodb_2.0.0-1 Target version: php-mongodb_2.0.0-1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/php-mongodb/php-mongodb_2.0.0-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/php-mongodb/php-mongodb_2.0.0-1+deb13u1.dsc changelog | 22 + gbp.conf | 2 patches/0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch | 100 ++++ patches/0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch | 72 +++ patches/0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch | 220 ++++++++++ patches/0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch | 118 +++++ patches/0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch | 33 + patches/0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch | 166 +++++++ patches/0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch | 206 +++++++++ patches/series | 7 10 files changed, 945 insertions(+), 1 deletion(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpir137xpv/php-mongodb_2.0.0-1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpir137xpv/php-mongodb_2.0.0-1+deb13u1.dsc: no acceptable signature found diff -Nru php-mongodb-2.0.0/debian/changelog php-mongodb-2.0.0/debian/changelog --- php-mongodb-2.0.0/debian/changelog 2025-04-19 09:11:29.000000000 +0000 +++ php-mongodb-2.0.0/debian/changelog 2026-10-01 06:25:18.000000000 +0000 @@ -1,3 +1,25 @@ +php-mongodb (2.0.0-1+deb13u1) trixie-security; urgency=high + + * PHPC-2744: Fix out-of-bounds read of field path + + [CVE-2026-84968]: An out-of-bounds read in the BSON decoding + component of the MongoDB PHP driver may allow an unauthenticated + party who supplies specially formed input to have a small amount of + adjacent process memory copied into an error message that is returned + to application code. This may result in unintended disclosure of + limited memory contents. + * PHPC-2743: Fix __pclass inference in events + + [CVE-2026-96745]: Deserialization of untrusted data in the command + monitoring support of the MongoDB PHP Driver can cause class names + embedded in document content to be honored when the driver builds + monitoring event objects. + * PHPC-2636: Respect libbson nesting limit when parsing PHP objects + + [CVE-2026-6811]: Stack exhaustion vulnerability in the MongoDB PHP + driver can cause application crashes when processing deeply nested + BSON documents in unusual circumstances when the source of these BSON + documents is not MongoDB Server. + + -- Ondřej Surý Thu, 01 Oct 2026 08:25:18 +0200 + php-mongodb (2.0.0-1) unstable; urgency=medium * New upstream version 2.0.0 diff -Nru php-mongodb-2.0.0/debian/gbp.conf php-mongodb-2.0.0/debian/gbp.conf --- php-mongodb-2.0.0/debian/gbp.conf 2025-04-19 09:11:29.000000000 +0000 +++ php-mongodb-2.0.0/debian/gbp.conf 2026-10-01 06:25:18.000000000 +0000 @@ -1,5 +1,5 @@ [DEFAULT] -debian-branch = debian/main +debian-branch = debian/trixie debian-tag = debian/%(version)s upstream-branch = upstream upstream-tag = upstream/%(version)s diff -Nru php-mongodb-2.0.0/debian/patches/0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch php-mongodb-2.0.0/debian/patches/0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch --- php-mongodb-2.0.0/debian/patches/0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,100 @@ +From: =?utf-8?b?SsOpcsO0bWUgVGFtYXJlbGxl?= +Date: Sun, 23 Aug 2026 23:47:01 +0200 +Subject: PHPC-2744: Fix out-of-bounds read of field path and limit BSON + nesting depth + +--- + mongodb-2.0.0/src/phongo_bson.c | 16 ++++++++-- + mongodb-2.0.0/tests/bson/bug-phpc-2744.phpt | 47 ++++++++++++++++++++++++++++ + 2 files changed, 60 insertions(+), 3 deletions(-) + create mode 100644 mongodb-2.0.0/tests/bson/bug-phpc-2744.phpt + +--- a/mongodb-2.0.0/src/phongo_bson.c ++++ b/mongodb-2.0.0/src/phongo_bson.c +@@ -87,7 +87,12 @@ + return estrdup(""); + } + +- for (i = 0; i <= field_path->size; i++) { ++ /* Iterate up to and including "size", since the element for the current ++ * level is stored at that index and is only counted once the level is ++ * pushed. That index is not always allocated: the array only grows when an ++ * element is written to it, so stop at "allocated_size" to avoid reading ++ * past the end of the array. */ ++ for (i = 0; i <= field_path->size && i < field_path->allocated_size; i++) { + if (!field_path->elements[i]) { + continue; + } +@@ -97,7 +102,7 @@ + path = emalloc(length); + ptr = path; + +- for (i = 0; i <= field_path->size; i++) { ++ for (i = 0; i <= field_path->size && i < field_path->allocated_size; i++) { + if (!field_path->elements[i]) { + continue; + } +@@ -106,7 +111,12 @@ + ptr[0] = '.'; + ptr++; + } +- ptr[-1] = '\0'; ++ ++ if (ptr == path) { ++ path[0] = '\0'; ++ } else { ++ ptr[-1] = '\0'; ++ } + + return path; + } +--- /dev/null ++++ b/mongodb-2.0.0/tests/bson/bug-phpc-2744.phpt +@@ -0,0 +1,47 @@ ++--TEST-- ++PHPC-2744: Field path for corrupt BSON at a nesting depth that is a multiple of 8 ++--DESCRIPTION-- ++The field path element for the current level is stored at index "size", which may ++be past the end of the allocation when the depth is a multiple of the allocation ++step. Reading it leaked heap memory into the exception message. ++--FILE-- ++ 'bar']; ++ ++ for ($i = 0; $i < $depth; $i++) { ++ $value = ['a' => $value]; ++ } ++ ++ return $value; ++} ++ ++foreach ([7, 8, 9, 15, 16, 17] as $depth) { ++ $bson = str_replace('INVALID!', "INVALID\xFE", fromPHP(nest($depth))); ++ ++ echo throws(function() use ($bson) { ++ MongoDB\BSON\Document::fromBSON($bson)->toPHP(); ++ }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ++} ++ ++?> ++===DONE=== ++ ++--EXPECT-- ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a' at offset 0 ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a.a' at offset 0 ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a.a.a' at offset 0 ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a' at offset 0 ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a' at offset 0 ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Detected corrupt BSON data for field path 'a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a' at offset 0 ++===DONE=== diff -Nru php-mongodb-2.0.0/debian/patches/0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch php-mongodb-2.0.0/debian/patches/0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch --- php-mongodb-2.0.0/debian/patches/0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,72 @@ +From: Pauline Vos +Date: Mon, 17 Aug 2026 15:43:25 +0200 +Subject: PHPC-2743: Add opt-out for __pclass class inference + +--- + mongodb-2.0.0/src/phongo_bson.c | 7 ++++++- + mongodb-2.0.0/src/phongo_bson.h | 24 ++++++++++++++++++++---- + 2 files changed, 26 insertions(+), 5 deletions(-) + +--- a/mongodb-2.0.0/src/phongo_bson.c ++++ b/mongodb-2.0.0/src/phongo_bson.c +@@ -227,6 +227,9 @@ + static void php_phongo_bson_state_copy_ctor(php_phongo_bson_state* dst, php_phongo_bson_state* src) + { + dst->map = src->map; ++ /* Must be inherited, or nested documents would infer an ODM class after the ++ * parent state suppressed it. */ ++ dst->skip_odm = src->skip_odm; + if (src->field_path) { + src->field_path->ref_count++; + } +@@ -300,7 +303,9 @@ + zval* retval = PHONGO_BSON_STATE_ZCHILD(data); + php_phongo_bson_state* state = (php_phongo_bson_state*) data; + +- if (v_subtype == 0x80 && strcmp(key, PHONGO_ODM_FIELD_NAME) == 0) { ++ /* Deliberately checked before fetching the class, as fetching it would run ++ * autoloaders on a class name taken straight from the BSON. */ ++ if (!state->skip_odm && v_subtype == 0x80 && strcmp(key, PHONGO_ODM_FIELD_NAME) == 0) { + zend_string* zs_classname = zend_string_init((const char*) v_binary, v_binary_len, 0); + zend_class_entry* found_ce = zend_fetch_class(zs_classname, ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_SILENT); + zend_string_release(zs_classname); +--- a/mongodb-2.0.0/src/phongo_bson.h ++++ b/mongodb-2.0.0/src/phongo_bson.h +@@ -71,10 +71,15 @@ + } php_phongo_bson_typemap; + + typedef struct { +- zval zchild; +- php_phongo_bson_typemap map; +- zend_class_entry* odm_ce; +- bool is_visiting_array; ++ zval zchild; ++ php_phongo_bson_typemap map; ++ zend_class_entry* odm_ce; ++ bool is_visiting_array; ++ /* Suppresses inference of an ODM class from the "__pclass" field. Set for ++ * driver-internal conversions, where the BSON may originate from a server ++ * reply or from data the application does not control, and where there is ++ * no type map through which a caller could opt out. */ ++ bool skip_odm; + php_phongo_field_path* field_path; + php_phongo_bson_typemap_element field_type; + } php_phongo_bson_state; +@@ -97,6 +102,17 @@ + s.map.document.type = PHONGO_TYPEMAP_NATIVE_ARRAY; \ + } while (0) + ++/* Initializes a state for a driver-internal conversion that yields objects. The ++ * type map is explicit rather than left as PHONGO_TYPEMAP_NONE, which would be ++ * interpreted as a request to infer the class from a "__pclass" field. */ ++#define PHONGO_BSON_INIT_INTERNAL_STATE(s) \ ++ do { \ ++ memset(&(s), 0, sizeof(php_phongo_bson_state)); \ ++ s.skip_odm = true; \ ++ s.map.root.type = PHONGO_TYPEMAP_NATIVE_OBJECT; \ ++ s.map.document.type = PHONGO_TYPEMAP_NATIVE_OBJECT; \ ++ } while (0) ++ + char* php_phongo_field_path_as_string(php_phongo_field_path* field_path); + php_phongo_field_path* php_phongo_field_path_alloc(bool owns_elements); + void php_phongo_field_path_free(php_phongo_field_path* field_path); diff -Nru php-mongodb-2.0.0/debian/patches/0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch php-mongodb-2.0.0/debian/patches/0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch --- php-mongodb-2.0.0/debian/patches/0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,220 @@ +From: Pauline Vos +Date: Mon, 17 Aug 2026 15:46:53 +0200 +Subject: PHPC-2743: Do not infer ODM class in command monitoring events + +The monitoring events decoded the observed command and reply with a zeroed +conversion state, which requests inference of an ODM class from a +"__pclass" field. Data an application writes into a document could +therefore have an attacker-chosen class autoloaded, instantiated without +its constructor, and passed the decoded data via bsonUnserialize(), all +inside the subscriber callback. For a started event this happens before the +command reaches the server. Subscribers had no way to opt out, as APM +exposes no type map. + +Both the accessor and the debug handler of each event decode the observed +document, so both are converted. The accessors declare an object return +type and now yield stdClass; the "__pclass" field itself is still reported, +as a Binary. + +ServerHeartbeatSucceededEvent is included: it decodes the hello reply +through the same path. +--- + .../src/MongoDB/Monitoring/CommandFailedEvent.c | 4 +- + .../src/MongoDB/Monitoring/CommandStartedEvent.c | 4 +- + .../src/MongoDB/Monitoring/CommandSucceededEvent.c | 4 +- + .../Monitoring/ServerHeartbeatSucceededEvent.c | 4 +- + .../tests/apm/commandStartedEvent-pclass-001.phpt | 108 +++++++++++++++++++++ + 5 files changed, 116 insertions(+), 8 deletions(-) + create mode 100644 mongodb-2.0.0/tests/apm/commandStartedEvent-pclass-001.phpt + +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandFailedEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandFailedEvent.c +@@ -111,7 +111,7 @@ + php_phongo_commandfailedevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); + + intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); + +@@ -216,7 +216,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_STATE(reply_state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); + + intern = Z_OBJ_COMMANDFAILEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandStartedEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandStartedEvent.c +@@ -36,7 +36,7 @@ + php_phongo_commandstartedevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); + + intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); + +@@ -190,7 +190,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state command_state; + +- PHONGO_BSON_INIT_STATE(command_state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(command_state); + + intern = Z_OBJ_COMMANDSTARTEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandSucceededEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandSucceededEvent.c +@@ -100,7 +100,7 @@ + php_phongo_commandsucceededevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); + + intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); + +@@ -201,7 +201,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_STATE(reply_state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); + + intern = Z_OBJ_COMMANDSUCCEEDEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c +@@ -61,7 +61,7 @@ + php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); + + PHONGO_PARSE_PARAMETERS_NONE(); + +@@ -115,7 +115,7 @@ + zval retval = ZVAL_STATIC_INIT; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_STATE(reply_state); ++ PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); + + intern = Z_OBJ_SERVERHEARTBEATSUCCEEDEDEVENT(object); + *is_temp = 1; +--- /dev/null ++++ b/mongodb-2.0.0/tests/apm/commandStartedEvent-pclass-001.phpt +@@ -0,0 +1,108 @@ ++--TEST-- ++PHPC-2743: CommandStartedEvent does not infer a class from __pclass ++--SKIPIF-- ++ ++ ++ ++--FILE-- ++getCommand(); ++ ++ /* The injected __pclass sits in the filter for a query and at the root ++ * for a command document. Report whichever applies. Every access is ++ * null-safe so that an inferred class still reports rather than ++ * aborting the test. */ ++ $subject = $command->filter ?? $command; ++ ++ printf("subject: %s\n", get_debug_type($subject)); ++ printf("subject.__pclass: %s\n", get_debug_type($subject->__pclass ?? null)); ++ ++ if (isset($subject->nested)) { ++ printf("subject.nested: %s\n", get_debug_type($subject->nested)); ++ printf("subject.nested.__pclass: %s\n", get_debug_type($subject->nested->__pclass ?? null)); ++ } ++ ++ /* The debug handler decodes the command a second time. Assert only that ++ * it reports no Gadget, rather than matching the whole format. */ ++ ob_start(); ++ var_dump($event); ++ $debug = ob_get_clean(); ++ printf("debug has Gadget instance: %s\n", str_contains($debug, 'object(Gadget)') ? 'yes' : 'no'); ++ } ++ ++ public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void ++ { ++ } ++ ++ public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void ++ { ++ } ++} ++ ++MongoDB\Driver\Monitoring\addSubscriber(new MySubscriber()); ++ ++$manager = create_test_manager(); ++$pclass = sprintf('{"$binary":{"base64":"%s","subType":"80"}}', base64_encode('Gadget')); ++ ++echo "\n=== __pclass nested in a query filter ===\n"; ++$manager->executeQuery(NS, new MongoDB\Driver\Query( ++ MongoDB\BSON\Document::fromJSON(sprintf('{"__pclass":%s}', $pclass)) ++)); ++ ++echo "\n=== __pclass nested deeper in a query filter ===\n"; ++$manager->executeQuery(NS, new MongoDB\Driver\Query( ++ MongoDB\BSON\Document::fromJSON(sprintf('{"nested":{"__pclass":%s}}', $pclass)) ++)); ++ ++echo "\n=== __pclass at the root of a command document ===\n"; ++try { ++ $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command( ++ MongoDB\BSON\Document::fromJSON(sprintf('{"ping":1,"__pclass":%s}', $pclass)) ++ )); ++} catch (MongoDB\Driver\Exception\Exception $e) { ++ /* The server may reject an unrecognized field, which is irrelevant here: ++ * the event is dispatched before the command is sent. */ ++} ++ ++?> ++===DONE=== ++ ++--EXPECT-- ++=== __pclass nested in a query filter === ++subject: stdClass ++subject.__pclass: MongoDB\BSON\Binary ++debug has Gadget instance: no ++ ++=== __pclass nested deeper in a query filter === ++subject: stdClass ++subject.__pclass: null ++subject.nested: stdClass ++subject.nested.__pclass: MongoDB\BSON\Binary ++debug has Gadget instance: no ++ ++=== __pclass at the root of a command document === ++subject: stdClass ++subject.__pclass: MongoDB\BSON\Binary ++debug has Gadget instance: no ++===DONE=== diff -Nru php-mongodb-2.0.0/debian/patches/0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch php-mongodb-2.0.0/debian/patches/0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch --- php-mongodb-2.0.0/debian/patches/0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,118 @@ +From: Pauline Vos +Date: Mon, 17 Aug 2026 15:50:12 +0200 +Subject: PHPC-2743: Do not infer ODM class when decoding server error replies + +The reply attached to CommandException, and the "errInfo" document of a +write error or write concern error, were decoded with the default type map, +which requests inference of an ODM class from a "__pclass" field. A server +reply could therefore have a class of its choosing autoloaded, instantiated +without its constructor, and passed the decoded data. + +Unlike the command monitoring events, these paths are not reachable with +data an application merely writes: the server does not echo the submitted +document back in an error reply. They require a malicious or compromised +server, so this is defence in depth rather than a fix for the same exposure. + +Add internal variants of the two default-type-map helpers, as the existing +ones are shared with debug handlers that decode documents supplied by the +caller and must keep inferring. +--- + mongodb-2.0.0/src/MongoDB/WriteConcernError.c | 2 +- + mongodb-2.0.0/src/MongoDB/WriteError.c | 2 +- + mongodb-2.0.0/src/phongo_bson.c | 30 ++++++++++++++++++++++++++ + mongodb-2.0.0/src/phongo_bson.h | 2 ++ + mongodb-2.0.0/src/phongo_error.c | 2 +- + 5 files changed, 35 insertions(+), 3 deletions(-) + +--- a/mongodb-2.0.0/src/MongoDB/WriteConcernError.c ++++ b/mongodb-2.0.0/src/MongoDB/WriteConcernError.c +@@ -160,7 +160,7 @@ + + bson_iter_document(&iter, &len, &data); + +- if (!php_phongo_bson_data_to_zval(data, len, &intern->info)) { ++ if (!php_phongo_bson_data_to_zval_internal(data, len, &intern->info)) { + zval_ptr_dtor(&intern->info); + ZVAL_UNDEF(&intern->info); + +--- a/mongodb-2.0.0/src/MongoDB/WriteError.c ++++ b/mongodb-2.0.0/src/MongoDB/WriteError.c +@@ -171,7 +171,7 @@ + + bson_iter_document(&iter, &len, &data); + +- if (!php_phongo_bson_data_to_zval(data, len, &intern->info)) { ++ if (!php_phongo_bson_data_to_zval_internal(data, len, &intern->info)) { + zval_ptr_dtor(&intern->info); + ZVAL_UNDEF(&intern->info); + +--- a/mongodb-2.0.0/src/phongo_bson.c ++++ b/mongodb-2.0.0/src/phongo_bson.c +@@ -909,6 +909,21 @@ + return retval; + } + ++/* Converts a BSON document originating from the server or the driver itself to ++ * a PHP value, without inferring an ODM class from a "__pclass" field. */ ++bool php_phongo_bson_to_zval_internal(const bson_t* b, zval* zv) ++{ ++ bool retval; ++ php_phongo_bson_state state; ++ ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ ++ retval = php_phongo_bson_to_zval_ex(b, &state); ++ ZVAL_ZVAL(zv, &state.zchild, 1, 1); ++ ++ return retval; ++} ++ + /* Converts BSON data to a PHP value using the default typemap. */ + bool php_phongo_bson_data_to_zval(const unsigned char* data, int data_len, zval* zv) + { +@@ -919,6 +934,21 @@ + + retval = php_phongo_bson_data_to_zval_ex(data, data_len, &state); + ZVAL_ZVAL(zv, &state.zchild, 1, 1); ++ ++ return retval; ++} ++ ++/* Converts BSON data originating from the server or the driver itself to a PHP ++ * value, without inferring an ODM class from a "__pclass" field. */ ++bool php_phongo_bson_data_to_zval_internal(const unsigned char* data, int data_len, zval* zv) ++{ ++ bool retval; ++ php_phongo_bson_state state; ++ ++ PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ ++ retval = php_phongo_bson_data_to_zval_ex(data, data_len, &state); ++ ZVAL_ZVAL(zv, &state.zchild, 1, 1); + + return retval; + } +--- a/mongodb-2.0.0/src/phongo_bson.h ++++ b/mongodb-2.0.0/src/phongo_bson.h +@@ -123,8 +123,10 @@ + + bool php_phongo_bson_to_json(zval* return_value, const bson_t* bson, php_phongo_json_mode_t mode); + bool php_phongo_bson_to_zval(const bson_t* b, zval* zv); ++bool php_phongo_bson_to_zval_internal(const bson_t* b, zval* zv); + bool php_phongo_bson_to_zval_ex(const bson_t* b, php_phongo_bson_state* state); + bool php_phongo_bson_data_to_zval(const unsigned char* data, int data_len, zval* zv); ++bool php_phongo_bson_data_to_zval_internal(const unsigned char* data, int data_len, zval* zv); + bool php_phongo_bson_data_to_zval_ex(const unsigned char* data, int data_len, php_phongo_bson_state* state); + + bool phongo_bson_value_to_zval(const bson_value_t* value, zval* zv); +--- a/mongodb-2.0.0/src/phongo_error.c ++++ b/mongodb-2.0.0/src/phongo_error.c +@@ -194,7 +194,7 @@ + zval zv; + + zend_throw_exception(php_phongo_commandexception_ce, error->message, error->code); +- if (php_phongo_bson_to_zval(reply, &zv)) { ++ if (php_phongo_bson_to_zval_internal(reply, &zv)) { + phongo_add_exception_prop(ZEND_STRL("resultDocument"), &zv); + } + diff -Nru php-mongodb-2.0.0/debian/patches/0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch php-mongodb-2.0.0/debian/patches/0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch --- php-mongodb-2.0.0/debian/patches/0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,33 @@ +From: Pauline Vos +Date: Mon, 17 Aug 2026 15:51:10 +0200 +Subject: PHPC-2743: Do not infer ODM class when decoding write results + +--- + mongodb-2.0.0/src/MongoDB/WriteResult.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/mongodb-2.0.0/src/MongoDB/WriteResult.c ++++ b/mongodb-2.0.0/src/MongoDB/WriteResult.c +@@ -133,7 +133,7 @@ + } + + bson_iter_document(&child, &len, &data); +- php_phongo_bson_data_to_zval(data, len, &error_reply); ++ php_phongo_bson_data_to_zval_internal(data, len, &error_reply); + + add_next_index_zval(return_value, &error_reply); + } +@@ -252,9 +252,12 @@ + php_phongo_bson_state state; + + /* Use PHONGO_TYPEMAP_NATIVE_ARRAY for the root type so we can +- * easily access the "index" and "_id" fields. */ ++ * easily access the "index" and "_id" fields. Only the root type is ++ * overridden, so suppress ODM inference for the "_id" document ++ * rather than also forcing a document type. */ + PHONGO_BSON_INIT_STATE(state); + state.map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY; ++ state.skip_odm = true; + + if (!BSON_ITER_HOLDS_DOCUMENT(&child)) { + continue; diff -Nru php-mongodb-2.0.0/debian/patches/0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch php-mongodb-2.0.0/debian/patches/0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch --- php-mongodb-2.0.0/debian/patches/0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,166 @@ +From: Pauline Vos +Date: Mon, 17 Aug 2026 15:51:21 +0200 +Subject: PHPC-2743: Do not infer ODM class in ClientEncryption and Session + +--- + mongodb-2.0.0/src/MongoDB/ClientEncryption.c | 4 ++-- + mongodb-2.0.0/src/MongoDB/Monitoring/CommandFailedEvent.c | 4 ++-- + mongodb-2.0.0/src/MongoDB/Monitoring/CommandStartedEvent.c | 4 ++-- + mongodb-2.0.0/src/MongoDB/Monitoring/CommandSucceededEvent.c | 4 ++-- + mongodb-2.0.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c | 4 ++-- + mongodb-2.0.0/src/MongoDB/Session.c | 4 ++-- + mongodb-2.0.0/src/phongo_bson.c | 4 ++-- + mongodb-2.0.0/src/phongo_bson.h | 2 +- + 8 files changed, 15 insertions(+), 15 deletions(-) + +--- a/mongodb-2.0.0/src/MongoDB/ClientEncryption.c ++++ b/mongodb-2.0.0/src/MongoDB/ClientEncryption.c +@@ -44,7 +44,7 @@ + #define RETVAL_BSON_T(reply) \ + do { \ + php_phongo_bson_state state; \ +- PHONGO_BSON_INIT_STATE(state); \ ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); \ + if (!php_phongo_bson_to_zval_ex(&(reply), &state)) { \ + zval_ptr_dtor(&state.zchild); \ + goto cleanup; \ +@@ -1075,7 +1075,7 @@ + goto cleanup; + } + +- if (!php_phongo_bson_to_zval(&expr_encrypted, return_value)) { ++ if (!php_phongo_bson_to_zval_internal(&expr_encrypted, return_value)) { + /* Exception already thrown */ + goto cleanup; + } +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandFailedEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandFailedEvent.c +@@ -111,7 +111,7 @@ + php_phongo_commandfailedevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); + +@@ -216,7 +216,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(reply_state); + + intern = Z_OBJ_COMMANDFAILEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandStartedEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandStartedEvent.c +@@ -36,7 +36,7 @@ + php_phongo_commandstartedevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); + +@@ -190,7 +190,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state command_state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(command_state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(command_state); + + intern = Z_OBJ_COMMANDSTARTEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/CommandSucceededEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/CommandSucceededEvent.c +@@ -100,7 +100,7 @@ + php_phongo_commandsucceededevent_t* intern; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); + +@@ -201,7 +201,7 @@ + char operation_id[24], request_id[24]; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(reply_state); + + intern = Z_OBJ_COMMANDSUCCEEDEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c ++++ b/mongodb-2.0.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c +@@ -61,7 +61,7 @@ + php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + PHONGO_PARSE_PARAMETERS_NONE(); + +@@ -115,7 +115,7 @@ + zval retval = ZVAL_STATIC_INIT; + php_phongo_bson_state reply_state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(reply_state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(reply_state); + + intern = Z_OBJ_SERVERHEARTBEATSUCCEEDEDEVENT(object); + *is_temp = 1; +--- a/mongodb-2.0.0/src/MongoDB/Session.c ++++ b/mongodb-2.0.0/src/MongoDB/Session.c +@@ -213,7 +213,7 @@ + const bson_t* cluster_time; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + intern = Z_SESSION_OBJ_P(getThis()); + SESSION_CHECK_LIVELINESS(intern, "getClusterTime") +@@ -242,7 +242,7 @@ + const bson_t* lsid; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + intern = Z_SESSION_OBJ_P(getThis()); + SESSION_CHECK_LIVELINESS(intern, "getLogicalSessionId") +--- a/mongodb-2.0.0/src/phongo_bson.c ++++ b/mongodb-2.0.0/src/phongo_bson.c +@@ -916,7 +916,7 @@ + bool retval; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + retval = php_phongo_bson_to_zval_ex(b, &state); + ZVAL_ZVAL(zv, &state.zchild, 1, 1); +@@ -945,7 +945,7 @@ + bool retval; + php_phongo_bson_state state; + +- PHONGO_BSON_INIT_INTERNAL_STATE(state); ++ PHONGO_BSON_INIT_NO_ODM_STATE(state); + + retval = php_phongo_bson_data_to_zval_ex(data, data_len, &state); + ZVAL_ZVAL(zv, &state.zchild, 1, 1); +--- a/mongodb-2.0.0/src/phongo_bson.h ++++ b/mongodb-2.0.0/src/phongo_bson.h +@@ -105,7 +105,7 @@ + /* Initializes a state for a driver-internal conversion that yields objects. The + * type map is explicit rather than left as PHONGO_TYPEMAP_NONE, which would be + * interpreted as a request to infer the class from a "__pclass" field. */ +-#define PHONGO_BSON_INIT_INTERNAL_STATE(s) \ ++#define PHONGO_BSON_INIT_NO_ODM_STATE(s) \ + do { \ + memset(&(s), 0, sizeof(php_phongo_bson_state)); \ + s.skip_odm = true; \ diff -Nru php-mongodb-2.0.0/debian/patches/0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch php-mongodb-2.0.0/debian/patches/0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch --- php-mongodb-2.0.0/debian/patches/0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,206 @@ +From 2060beb85a041182550d022ec223783ffdaf6ec8 Mon Sep 17 00:00:00 2001 +From: Andreas Braun +Date: Wed, 4 Feb 2026 15:43:01 +0100 +Subject: [PATCH] PHPC-2636: Respect libbson nesting limit when parsing PHP + objects (#1934) + +--- + src/phongo_bson.c | 7 ++-- + src/phongo_bson.h | 1 + + src/phongo_bson_encode.c | 25 ++++++++++---- + tests/bson/bson-document-fromPHP-005.phpt | 34 ++++++++++++++++++++ + tests/bson/bson-document-fromPHP-006.phpt | 34 ++++++++++++++++++++ + tests/bson/bson-packedarray-fromPHP-002.phpt | 34 ++++++++++++++++++++ + 6 files changed, 126 insertions(+), 9 deletions(-) + create mode 100644 tests/bson/bson-document-fromPHP-005.phpt + create mode 100644 tests/bson/bson-document-fromPHP-006.phpt + create mode 100644 tests/bson/bson-packedarray-fromPHP-002.phpt + +--- a/mongodb-2.0.0/src/phongo_bson.c ++++ b/mongodb-2.0.0/src/phongo_bson.c +@@ -191,12 +191,15 @@ + + bool php_phongo_field_path_push(php_phongo_field_path* field_path, const char* element, php_phongo_bson_field_path_item_types element_type) + { +- php_phongo_field_path_write_item_at_current_level(field_path, element); ++ if (element) { ++ php_phongo_field_path_write_item_at_current_level(field_path, element); ++ } ++ + php_phongo_field_path_write_type_at_current_level(field_path, element_type); + + field_path->size++; + +- return true; ++ return field_path->size <= BSON_MAX_NESTING_LEVEL; + } + + bool php_phongo_field_path_pop(php_phongo_field_path* field_path) +--- a/mongodb-2.0.0/src/phongo_bson.h ++++ b/mongodb-2.0.0/src/phongo_bson.h +@@ -24,6 +24,7 @@ + #define BSON_UNSERIALIZE_FUNC_NAME "bsonUnserialize" + #define BSON_SERIALIZE_FUNC_NAME "bsonSerialize" + #define PHONGO_ODM_FIELD_NAME "__pclass" ++#define BSON_MAX_NESTING_LEVEL 100 + + typedef enum { + PHONGO_FIELD_PATH_ITEM_NONE, +--- a/mongodb-2.0.0/src/phongo_bson_encode.c ++++ b/mongodb-2.0.0/src/phongo_bson_encode.c +@@ -357,11 +357,15 @@ + break; + } + ++ if (!php_phongo_field_path_push(field_path, NULL, PHONGO_FIELD_PATH_ITEM_ARRAY)) { ++ phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Nesting level too deep"); ++ php_phongo_zend_hash_apply_protection_end(tmp_ht); ++ break; ++ } ++ + bson_append_array_begin(bson, key, key_len, &child); +- php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_ARRAY); +- field_path->size++; + php_phongo_zval_to_bson_internal(entry, field_path, flags, &child, NULL); +- field_path->size--; ++ php_phongo_field_path_pop(field_path); + bson_append_array_end(bson, &child); + + php_phongo_zend_hash_apply_protection_end(tmp_ht); +@@ -380,14 +384,21 @@ + } + + if (Z_TYPE_P(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_P(entry), php_phongo_packedarray_ce)) { +- php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_ARRAY); ++ if (!php_phongo_field_path_push(field_path, NULL, PHONGO_FIELD_PATH_ITEM_ARRAY)) { ++ phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Nesting level too deep"); ++ php_phongo_zend_hash_apply_protection_end(tmp_ht); ++ break; ++ } + } else { +- php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_DOCUMENT); ++ if (!php_phongo_field_path_push(field_path, NULL, PHONGO_FIELD_PATH_ITEM_DOCUMENT)) { ++ phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Nesting level too deep"); ++ php_phongo_zend_hash_apply_protection_end(tmp_ht); ++ break; ++ } + } + +- field_path->size++; + php_phongo_bson_append_object(bson, field_path, flags, key, key_len, entry); +- field_path->size--; ++ php_phongo_field_path_pop(field_path); + + php_phongo_zend_hash_apply_protection_end(tmp_ht); + break; +--- /dev/null ++++ b/mongodb-2.0.0/tests/bson/bson-document-fromPHP-005.phpt +@@ -0,0 +1,34 @@ ++--TEST-- ++MongoDB\BSON\Document::fromPHP() respects nesting limit for BSON objects (from array) ++--FILE-- ++ $value]; ++ } ++ ++ return $value; ++} ++ ++echo "Creating document with 100 levels of nesting\n"; ++MongoDB\BSON\Document::fromPHP(createNestedArray(100)); ++ ++echo "Creating document with 101 levels of nesting\n"; ++echo throws(function() { ++ MongoDB\BSON\Document::fromPHP(createNestedArray(101)); ++}, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ++ ++?> ++===DONE=== ++ ++--EXPECT-- ++Creating document with 100 levels of nesting ++Creating document with 101 levels of nesting ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Nesting level too deep ++===DONE=== +--- /dev/null ++++ b/mongodb-2.0.0/tests/bson/bson-document-fromPHP-006.phpt +@@ -0,0 +1,34 @@ ++--TEST-- ++MongoDB\BSON\Document::fromPHP() respects nesting limit for BSON objects (from object) ++--FILE-- ++ $value]; ++ } ++ ++ return $value; ++} ++ ++echo "Creating document with 100 levels of nesting\n"; ++MongoDB\BSON\Document::fromPHP(createNestedObject(100)); ++ ++echo "Creating document with 101 levels of nesting\n"; ++echo throws(function() { ++ MongoDB\BSON\Document::fromPHP(createNestedObject(101)); ++}, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ++ ++?> ++===DONE=== ++ ++--EXPECT-- ++Creating document with 100 levels of nesting ++Creating document with 101 levels of nesting ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Nesting level too deep ++===DONE=== +--- /dev/null ++++ b/mongodb-2.0.0/tests/bson/bson-packedarray-fromPHP-002.phpt +@@ -0,0 +1,34 @@ ++--TEST-- ++MongoDB\BSON\PackedArray::fromPHP() respects nesting limit ++--FILE-- ++ ++===DONE=== ++ ++--EXPECT-- ++Creating packed array with 100 levels of nesting ++Creating packed array with 101 levels of nesting ++OK: Got MongoDB\Driver\Exception\UnexpectedValueException ++Nesting level too deep ++===DONE=== diff -Nru php-mongodb-2.0.0/debian/patches/series php-mongodb-2.0.0/debian/patches/series --- php-mongodb-2.0.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ php-mongodb-2.0.0/debian/patches/series 2026-10-01 06:25:18.000000000 +0000 @@ -0,0 +1,7 @@ +0001-PHPC-2744-Fix-out-of-bounds-read-of-field-path-and-l.patch +0002-PHPC-2743-Add-opt-out-for-__pclass-class-inference.patch +0003-PHPC-2743-Do-not-infer-ODM-class-in-command-monitori.patch +0004-PHPC-2743-Do-not-infer-ODM-class-when-decoding-serve.patch +0005-PHPC-2743-Do-not-infer-ODM-class-when-decoding-write.patch +0006-PHPC-2743-Do-not-infer-ODM-class-in-ClientEncryption.patch +0007-PHPC-2636-Respect-libbson-nesting-limit-when-parsing-PHP.patch