Package: release.debian.org
Severity: normal
Tags: trixie
User: [email protected]
Usertags: pu

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

[ Reason ]
Address the following issue:

  * Fix CVE-2026-81523: validate db and collection names

[ Impact ]
Without this fix, users and applications integrating libmongocrypt
components may be vulnerable to potential information modification or
disclosure.

[ Tests ]
The affected/changed code went through upstream code reviews. Also,
accompanying unit tests were implemented and executed in upstream's
extensive CI environment.

[ Risks ]
Code changes are minimal (to the extent possible), extensively
reviewed/tested, and low risk. There are no work arounds.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
Backport the following upstream change:
https://github.com/mongodb/libmongocrypt/commit/0f8d744a8c5e1877e40efd1c8b440e4eed1e2462

[ Other info ]
N/A


-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEIYZ1DR4ae5UL01q7ldFmTdL1kUIFAmqTAvUACgkQldFmTdL1
kUKkkA//esD+6cjeZ1BQd02CK+fEKxbx0v6cAHB9BMH7193s/SWqe8f0gQo0r53h
MHMw8l49riPzr/gabY+RgV1t1t+0QOs/6DxPfneR4WHonR8RCfZfhSocQSIexUov
T9TJ3WyVAWxU401eIWhKapwDGNaszssut0kKH/Ii1kFk8cd1QMgPICz9YmFOshXk
v8lW2YGpxusqqQUSfPVJ6gJEI30VDgei8X3g8LYFdkPXJsgPlKgE+RqvmBX6kxlC
jMYpYDGN0SSYmKLvpn2QVCcPaPkcTSQQPYnVsHPcjnWG+aU6Ju+Xdpaj9EGfmIm4
mCMMw9nGff3+B9yC16ZKAz8HTEPadfBun3yzyDtabN3iUr1Fm1nNQgUGEkd8iXh4
srncjW6M1rvFZmfdgDnk0h4IWhIC8YC6T2TgtocUeur6Epq76Z46qGF51NtRPN5j
AbAXPjbx8caztIpZUzF6oQyi5FnhfpcCKjUNKSRUeb4O7w4Ojahq4xU/ZiCSr9o9
cLAiNOQGb7o5237bzOX9SNd6vJqOFzSgoOzlggTur4R9IwAcH2IAVzlkyNuxXwW6
iwTMuNkF/Z67hcgOll2bkVe6AolCrzEzGOPFrdE2uErDca6C8VKC1Y39lqSqB5Go
6NiZNDheuH4uu4ECrcbrC0CEAoDIKhDQYV4ZUh/IyhnPm9mzEfA=
=TYdC
-----END PGP SIGNATURE-----
diff -Nru libmongocrypt-1.13.2/debian/changelog 
libmongocrypt-1.13.2/debian/changelog
--- libmongocrypt-1.13.2/debian/changelog       2025-04-11 00:41:45.000000000 
-0400
+++ libmongocrypt-1.13.2/debian/changelog       2026-08-29 11:20:33.000000000 
-0400
@@ -1,3 +1,9 @@
+libmongocrypt (1.13.2-1+deb13u1) trixie; urgency=medium
+
+  * Fix CVE-2026-81523: validate db and collection names
+
+ -- Roberto C. Sanchez <[email protected]>  Sat, 29 Aug 2026 11:20:33 -0400
+
 libmongocrypt (1.13.2-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru libmongocrypt-1.13.2/debian/gbp.conf 
libmongocrypt-1.13.2/debian/gbp.conf
--- libmongocrypt-1.13.2/debian/gbp.conf        2025-04-11 00:41:45.000000000 
-0400
+++ libmongocrypt-1.13.2/debian/gbp.conf        2026-08-29 11:20:33.000000000 
-0400
@@ -12,9 +12,9 @@
     third_party_rm_files=\"$([ -d third-party ] && find third-party/ -mindepth 
1 -maxdepth 1 -printf '%p ')\" &&
     # Create upstream tarball from reference, exclude items that do not belong
     pushd $GBP_GIT_DIR/.. &&
-    git archive --format=tar --prefix=libmongocrypt-\${upstream_version}/ HEAD 
| tar -f - --delete libmongocrypt-\${upstream_version}/debian 
\$third_party_filter_files | gzip > 
$GBP_BUILD_DIR/../libmongocrypt_\${upstream_version}.orig.tar.gz &&
+    ( [ -f $GBP_BUILD_DIR/../libmongocrypt_\${upstream_version}.orig.tar.gz ] 
|| git archive --format=tar --prefix=libmongocrypt-\${upstream_version}/ HEAD | 
tar -f - --delete libmongocrypt-\${upstream_version}/debian 
\$third_party_filter_files | gzip > 
$GBP_BUILD_DIR/../libmongocrypt_\${upstream_version}.orig.tar.gz ) &&
     popd &&
     rm -rf \$third_party_rm_files"
 
 upstream-tag = %(version)s
-debian-branch = debian/unstable
+debian-branch = debian/trixie
diff -Nru libmongocrypt-1.13.2/debian/patches/0001_CVE-2026-81523.patch 
libmongocrypt-1.13.2/debian/patches/0001_CVE-2026-81523.patch
--- libmongocrypt-1.13.2/debian/patches/0001_CVE-2026-81523.patch       
1969-12-31 19:00:00.000000000 -0500
+++ libmongocrypt-1.13.2/debian/patches/0001_CVE-2026-81523.patch       
2026-08-29 11:20:33.000000000 -0400
@@ -0,0 +1,273 @@
+From 0f8d744a8c5e1877e40efd1c8b440e4eed1e2462 Mon Sep 17 00:00:00 2001
+From: Kevin Albertson <[email protected]>
+Date: Wed, 19 Aug 2026 07:48:21 -0400
+Subject: [PATCH] MONGOCRYPT-977 validate db and collection
+
+Reject NUL and dot in db.
+Reject NUL in collection.
+---
+ src/mc-schema-broker.c             |   12 +++
+ src/mongocrypt-ctx-encrypt.c       |   29 ++++++++-
+ src/mongocrypt-private.h           |    5 +
+ src/mongocrypt.c                   |   11 +++
+ test/test-mongocrypt-ctx-encrypt.c |  114 
+++++++++++++++++++++++++++++++++++++
+ 5 files changed, 165 insertions(+), 6 deletions(-)
+
+--- a/src/mc-schema-broker.c
++++ b/src/mc-schema-broker.c
+@@ -323,7 +323,11 @@
+             CLIENT_ERR("failed to find 'name' in collinfo in database: %s", 
sb->db);
+             return false;
+         }
+-        coll = bson_iter_utf8(&name_iter, NULL);
++        uint32_t coll_len;
++        coll = bson_iter_utf8(&name_iter, &coll_len);
++        if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, "collection 
name in collinfo", status)) {
++            return false;
++        }
+     }
+ 
+     // Cache the received collinfo.
+@@ -511,7 +515,11 @@
+         CLIENT_ERR("Failed to get collection name from command");
+         return false;
+     }
+-    const char *coll = bson_iter_utf8(&iter, NULL);
++    uint32_t coll_len;
++    const char *coll = bson_iter_utf8(&iter, &coll_len);
++    if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, "collection name", 
status)) {
++        return false;
++    }
+ 
+     // Check if schema was requested.
+     mc_schema_entry_t *found = NULL;
+--- a/src/mongocrypt-ctx-encrypt.c
++++ b/src/mongocrypt-ctx-encrypt.c
+@@ -2017,7 +2017,11 @@
+         return false;
+     }
+ 
+-    const char *target_ns = bson_iter_utf8(&ns_iter, NULL /* length */);
++    uint32_t target_ns_len;
++    const char *target_ns = bson_iter_utf8(&ns_iter, &target_ns_len);
++    if (!_mongocrypt_check_no_embedded_nul(target_ns, target_ns_len, 
"namespace in `bulkWrite` command", status)) {
++        return false;
++    }
+     // Parse `target_ns` into "<db>.<coll>"
+     const char *dot = strstr(target_ns, ".");
+     if (!dot) {
+@@ -2089,7 +2093,12 @@
+     }
+ 
+     if (BSON_ITER_HOLDS_UTF8(&target_coll_iter)) {
+-        *target_coll = bson_strdup(bson_iter_utf8(&target_coll_iter, NULL));
++        uint32_t target_coll_len;
++        const char *target_coll_str = bson_iter_utf8(&target_coll_iter, 
&target_coll_len);
++        if (!_mongocrypt_check_no_embedded_nul(target_coll_str, 
target_coll_len, "collection name", status)) {
++            return false;
++        }
++        *target_coll = bson_strdup(target_coll_str);
+     } else {
+         *target_coll = NULL;
+     }
+@@ -2277,7 +2286,11 @@
+                                    stage_key);
+                         return false;
+                     }
+-                    const char *from = bson_iter_utf8(&lookup_iter, NULL);
++                    uint32_t from_len;
++                    const char *from = bson_iter_utf8(&lookup_iter, 
&from_len);
++                    if (!_mongocrypt_check_no_embedded_nul(from, from_len, 
"'from' collection name", status)) {
++                        return false;
++                    }
+                     if (!mc_schema_broker_request(sb, db, from, status)) {
+                         return false;
+                     }
+@@ -2336,7 +2349,11 @@
+                                    stage_key);
+                         return false;
+                     }
+-                    const char *coll = bson_iter_utf8(&unionWith_iter, NULL);
++                    uint32_t coll_len;
++                    const char *coll = bson_iter_utf8(&unionWith_iter, 
&coll_len);
++                    if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, 
"'coll' collection name", status)) {
++                        return false;
++                    }
+                     if (!mc_schema_broker_request(sb, db, coll, status)) {
+                         return false;
+                     }
+@@ -2428,6 +2445,10 @@
+         return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
+     }
+ 
++    if (strchr(ectx->cmd_db, '.')) {
++        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db: must not contain 
a dot");
++    }
++
+     if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
+         // Handle `bulkWrite` as a special case.
+         // `bulkWrite` includes the target namespaces in an `nsInfo` field.
+--- a/src/mongocrypt-private.h
++++ b/src/mongocrypt-private.h
+@@ -153,6 +153,11 @@
+ 
+ bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, 
char **out) MONGOCRYPT_WARN_UNUSED_RESULT;
+ 
++/* _mongocrypt_check_no_embedded_nul returns false and sets @status if @str 
contains an embedded null byte. See
++ * MONGOCRYPT-977. */
++bool _mongocrypt_check_no_embedded_nul(const char *str, uint32_t len, const 
char *what, mongocrypt_status_t *status)
++    MONGOCRYPT_WARN_UNUSED_RESULT;
++
+ char *_mongocrypt_new_string_from_bytes(const void *in, int len);
+ 
+ char *_mongocrypt_new_json_string_from_binary(mongocrypt_binary_t *binary);
+--- a/src/mongocrypt.c
++++ b/src/mongocrypt.c
+@@ -985,6 +985,17 @@
+     return crypt->csfle.get_version();
+ }
+ 
++bool _mongocrypt_check_no_embedded_nul(const char *str, uint32_t len, const 
char *what, mongocrypt_status_t *status) {
++    BSON_ASSERT_PARAM(str);
++    BSON_ASSERT_PARAM(what);
++
++    if (strlen(str) != (size_t)len) {
++        CLIENT_ERR("%s must not contain an embedded null byte", what);
++        return false;
++    }
++    return true;
++}
++
+ bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, 
char **out) {
+     BSON_ASSERT_PARAM(out);
+ 
+--- a/test/test-mongocrypt-ctx-encrypt.c
++++ b/test/test-mongocrypt-ctx-encrypt.c
+@@ -360,6 +360,119 @@
+     mongocrypt_destroy(crypt);
+ }
+ 
++/* Test that a db name containing a dot or an embedded NUL is rejected.
++ * A db name like "a.b" would otherwise produce the namespace "a.b.coll",
++ * retargeting the operation at database "a" and collection "b.coll".
++ * Regression test for MONGOCRYPT-977. */
++static void _test_encrypt_init_invalid_db_collection(_mongocrypt_tester_t 
*tester) {
++    mongocrypt_t *crypt = 
_mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
++
++    {
++        /* Dot in db name. */
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "a.b", -1, 
TEST_FILE("./test/example/cmd.json")),
++                     ctx,
++                     "invalid db");
++        mongocrypt_ctx_destroy(ctx);
++    }
++
++    {
++        /* Embedded NUL in db name. */
++        const char db[] = "a\0b";
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, db, 3, 
TEST_FILE("./test/example/cmd.json")), ctx, "invalid db");
++        mongocrypt_ctx_destroy(ctx);
++    }
++
++    {
++        /* A dot in a collection name is legal, and must keep working. */
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "test", -1, 
TEST_BSON("{'find': 'a.b'}")), ctx);
++        mongocrypt_ctx_destroy(ctx);
++    }
++
++    {
++        /* Embedded NUL in the collection name of the command. */
++        bson_t *cmd = bson_new();
++        BSON_ASSERT(bson_append_utf8(cmd, "find", -1, "a\0b", 3));
++        mongocrypt_binary_t *bin = mongocrypt_binary_new_from_data((uint8_t 
*)bson_get_data(cmd), cmd->len);
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "test", -1, bin),
++                     ctx,
++                     "collection name must not contain an embedded null 
byte");
++        mongocrypt_ctx_destroy(ctx);
++        mongocrypt_binary_destroy(bin);
++        bson_destroy(cmd);
++    }
++
++    {
++        /* Embedded NUL in the `bulkWrite` nsInfo namespace. */
++        bson_t *cmd = bson_new();
++        bson_array_builder_t *nsInfo;
++        bson_t ns0;
++        BSON_ASSERT(BSON_APPEND_INT32(cmd, "bulkWrite", 1));
++        BSON_ASSERT(BSON_APPEND_ARRAY_BUILDER_BEGIN(cmd, "nsInfo", &nsInfo));
++        BSON_ASSERT(bson_array_builder_append_document_begin(nsInfo, &ns0));
++        BSON_ASSERT(bson_append_utf8(&ns0, "ns", -1, "db.coll\0evil", 12));
++        BSON_ASSERT(bson_array_builder_append_document_end(nsInfo, &ns0));
++        BSON_ASSERT(bson_append_array_builder_end(cmd, nsInfo));
++        mongocrypt_binary_t *bin = mongocrypt_binary_new_from_data((uint8_t 
*)bson_get_data(cmd), cmd->len);
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "test", -1, bin), ctx, 
"must not contain an embedded null byte");
++        mongocrypt_ctx_destroy(ctx);
++        mongocrypt_binary_destroy(bin);
++        bson_destroy(cmd);
++    }
++
++    {
++        /* Embedded NUL in a $lookup 'from' collection name. */
++        bson_t *cmd = bson_new();
++        bson_array_builder_t *pipeline;
++        bson_t stage, lookup;
++        BSON_ASSERT(BSON_APPEND_UTF8(cmd, "aggregate", "coll"));
++        BSON_ASSERT(BSON_APPEND_ARRAY_BUILDER_BEGIN(cmd, "pipeline", 
&pipeline));
++        BSON_ASSERT(bson_array_builder_append_document_begin(pipeline, 
&stage));
++        BSON_ASSERT(BSON_APPEND_DOCUMENT_BEGIN(&stage, "$lookup", &lookup));
++        BSON_ASSERT(bson_append_utf8(&lookup, "from", -1, "a\0b", 3));
++        BSON_ASSERT(bson_append_document_end(&stage, &lookup));
++        BSON_ASSERT(bson_array_builder_append_document_end(pipeline, &stage));
++        BSON_ASSERT(bson_append_array_builder_end(cmd, pipeline));
++        mongocrypt_binary_t *bin = mongocrypt_binary_new_from_data((uint8_t 
*)bson_get_data(cmd), cmd->len);
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "test", -1, bin),
++                     ctx,
++                     "'from' collection name must not contain an embedded 
null byte");
++        mongocrypt_ctx_destroy(ctx);
++        mongocrypt_binary_destroy(bin);
++        bson_destroy(cmd);
++    }
++
++    {
++        /* Embedded NUL in a $unionWith 'coll' collection name. */
++        bson_t *cmd = bson_new();
++        bson_array_builder_t *pipeline;
++        bson_t stage, unionWith;
++        BSON_ASSERT(BSON_APPEND_UTF8(cmd, "aggregate", "coll"));
++        BSON_ASSERT(BSON_APPEND_ARRAY_BUILDER_BEGIN(cmd, "pipeline", 
&pipeline));
++        BSON_ASSERT(bson_array_builder_append_document_begin(pipeline, 
&stage));
++        BSON_ASSERT(BSON_APPEND_DOCUMENT_BEGIN(&stage, "$unionWith", 
&unionWith));
++        BSON_ASSERT(bson_append_utf8(&unionWith, "coll", -1, "a\0b", 3));
++        BSON_ASSERT(bson_append_document_end(&stage, &unionWith));
++        BSON_ASSERT(bson_array_builder_append_document_end(pipeline, &stage));
++        BSON_ASSERT(bson_append_array_builder_end(cmd, pipeline));
++        mongocrypt_binary_t *bin = mongocrypt_binary_new_from_data((uint8_t 
*)bson_get_data(cmd), cmd->len);
++        mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
++        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "test", -1, bin),
++                     ctx,
++                     "'coll' collection name must not contain an embedded 
null byte");
++        mongocrypt_ctx_destroy(ctx);
++        mongocrypt_binary_destroy(bin);
++        bson_destroy(cmd);
++    }
++
++    mongocrypt_destroy(crypt);
++}
++
+ static void _test_encrypt_need_collinfo(_mongocrypt_tester_t *tester) {
+     mongocrypt_t *crypt;
+     mongocrypt_ctx_t *ctx;
+@@ -5796,6 +5909,7 @@
+ void _mongocrypt_tester_install_ctx_encrypt(_mongocrypt_tester_t *tester) {
+     INSTALL_TEST(_test_explicit_encrypt_init);
+     INSTALL_TEST(_test_encrypt_init);
++    INSTALL_TEST(_test_encrypt_init_invalid_db_collection);
+     INSTALL_TEST(_test_encrypt_need_collinfo);
+     INSTALL_TEST(_test_encrypt_need_markings);
+     INSTALL_TEST(_test_encrypt_csfle_no_needs_markings);
diff -Nru libmongocrypt-1.13.2/debian/patches/series 
libmongocrypt-1.13.2/debian/patches/series
--- libmongocrypt-1.13.2/debian/patches/series  1969-12-31 19:00:00.000000000 
-0500
+++ libmongocrypt-1.13.2/debian/patches/series  2026-08-29 11:20:33.000000000 
-0400
@@ -0,0 +1 @@
+0001_CVE-2026-81523.patch

Reply via email to