--- Begin Message ---
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
--- End Message ---