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-81524: 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/mongo-c-driver/commit/81d0f794d07224c53f815ceb59daed28103dcf3d

[ Other info ]
N/A


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

iQIzBAEBCgAdFiEEIYZ1DR4ae5UL01q7ldFmTdL1kUIFAmqTA6MACgkQldFmTdL1
kUL9OA/9H4GmIrMIkngE2ZATKuHBXhlCv+5SnWQy2HB4zi+rFHn3sEg0eNfXTR7w
qKRxWfD/XJsMU1owt9wtVj79bP+m/AAaNMgbjrqm0HT6eGG6npJwiCISH1WsBysb
U1EDRu2IgS06SaVsk2+MWONdP6K5jhQgv1s/VgPSrRjdN9y2rP2l+B1GKV+7w34f
c0Q+Q+YNfn+B0N89Xq0UN3ALse+EigXIyv6Li9nb9KjOk4FQKuEVzMMDW6ar6xeI
CsGTTGvGMsrBYCliEDOF3dNFhgKosv8JNgGs2Vbtq2IgItNQZHOeIw+z7mRM0ew1
JzSsf8LrCboM9zF9gaFsufkDcEWRGsaeHb2nG/cWzo5HQEZ4epYrReu1I3yrOPpX
rKtAz6aW9E4PFdJ1j4YME9Se5vLzRtyzFEe9Pg0xGznTx1l30OsbV0pintbwJwm8
DQKb2479hcAHhczoZhAdm1cO8JH5cDJxOySxaD5LPbtGiGIY2oia2CTzt7mqQklc
E322eFR8V7iMUsi11srb3HTyYWn/3vq72BJJBONZ5NBXFLQp1HgjcgNgQH8O7hSZ
jBTxt3UVmA6affa6j4MY/J5aBfbleDD/eixW7hBhlVBMI91b46mgFM76+XaMFqyR
zTla4LhLwYqigsWbqO2X4rEuBpiM1Q/ItytI7ikRPqBcP6yNqOo=
=cqRe
-----END PGP SIGNATURE-----
diff -Nru mongo-c-driver-1.30.4/debian/changelog 
mongo-c-driver-1.30.4/debian/changelog
--- mongo-c-driver-1.30.4/debian/changelog      2026-04-27 11:48:27.000000000 
-0400
+++ mongo-c-driver-1.30.4/debian/changelog      2026-08-29 11:06:27.000000000 
-0400
@@ -1,3 +1,9 @@
+mongo-c-driver (1.30.4-1+deb13u3) trixie; urgency=medium
+
+  * Fix CVE-2026-81524: validate db and collection names
+
+ -- Roberto C. Sanchez <[email protected]>  Sat, 29 Aug 2026 11:06:27 -0400
+
 mongo-c-driver (1.30.4-1+deb13u2) trixie; urgency=medium
 
   * Fix CVE-2026-6231: bson_validate may skip validation when processing
diff -Nru mongo-c-driver-1.30.4/debian/patches/0009_CVE-2026-81524.patch 
mongo-c-driver-1.30.4/debian/patches/0009_CVE-2026-81524.patch
--- mongo-c-driver-1.30.4/debian/patches/0009_CVE-2026-81524.patch      
1969-12-31 19:00:00.000000000 -0500
+++ mongo-c-driver-1.30.4/debian/patches/0009_CVE-2026-81524.patch      
2026-08-29 11:06:27.000000000 -0400
@@ -0,0 +1,443 @@
+From 81d0f794d07224c53f815ceb59daed28103dcf3d Mon Sep 17 00:00:00 2001
+From: Kevin Albertson <[email protected]>
+Date: Fri, 14 Aug 2026 12:39:43 -0400
+Subject: [PATCH] CDRIVER-6424 validate db and collection names
+
+---
+ src/libmongoc/src/mongoc/mongoc-aggregate-private.h      |    1 
+ src/libmongoc/src/mongoc/mongoc-aggregate.c              |    8 +
+ src/libmongoc/src/mongoc/mongoc-client-side-encryption.c |   12 ++
+ src/libmongoc/src/mongoc/mongoc-client.c                 |    4 
+ src/libmongoc/src/mongoc/mongoc-cmd.c                    |    7 +
+ src/libmongoc/src/mongoc/mongoc-collection.c             |   13 ++
+ src/libmongoc/src/mongoc/mongoc-cursor-private.h         |    4 
+ src/libmongoc/src/mongoc/mongoc-cursor.c                 |   15 ++
+ src/libmongoc/src/mongoc/mongoc-database.c               |    2 
+ src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c          |   16 +++
+ src/libmongoc/src/mongoc/mongoc-uri.c                    |   20 +++
+ src/libmongoc/src/mongoc/mongoc-util-private.h           |   34 ++++++
+ src/libmongoc/src/mongoc/mongoc-util.c                   |   76 
+++++++++++++++
+ 13 files changed, 211 insertions(+), 1 deletion(-)
+ create mode 100644 src/libmongoc/tests/test-mongoc-ns-validation.c
+
+--- a/src/libmongoc/src/mongoc/mongoc-aggregate-private.h
++++ b/src/libmongoc/src/mongoc/mongoc-aggregate-private.h
+@@ -34,6 +34,7 @@
+ mongoc_cursor_t *
+ _mongoc_aggregate (mongoc_client_t *client,
+                    const char *ns,
++                   const char *db,
+                    mongoc_query_flags_t flags,
+                    const bson_t *pipeline,
+                    const bson_t *opts,
+--- a/src/libmongoc/src/mongoc/mongoc-aggregate.c
++++ b/src/libmongoc/src/mongoc/mongoc-aggregate.c
+@@ -185,6 +185,7 @@
+  *       information on how to build aggregation pipelines.
+  *
+  * Parameters:
++ *       @db: Database name used. Separated from @ns to validate.
+  *       @ns: Namespace (or database name for database-level aggregation).
+  *       @flags: Bitwise or of mongoc_query_flags_t or 0.
+  *       @pipeline: A bson_t containing the pipeline request. @pipeline
+@@ -210,6 +211,7 @@
+ 
+ mongoc_cursor_t *
+ _mongoc_aggregate (mongoc_client_t *client,
++                   const char *db,
+                    const char *ns,
+                    mongoc_query_flags_t flags,
+                    const bson_t *pipeline,
+@@ -237,6 +239,7 @@
+ 
+    BSON_ASSERT (client);
+    BSON_ASSERT (ns);
++   BSON_ASSERT_PARAM(db);
+    BSON_ASSERT (pipeline);
+ 
+    bson_init (&cursor_opts);
+@@ -274,6 +277,11 @@
+       GOTO (done);
+    }
+ 
++   // `ns` is already joined and cannot be split back into `db` reliably. 
Check `db` while it is still separate.
++   if (!_mongoc_cursor_check_db_name(cursor, db)) {
++      GOTO(done);
++   }
++
+    if (!_mongoc_read_prefs_validate (cursor->read_prefs, &cursor->error)) {
+       GOTO (done);
+    }
+--- a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c
++++ b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c
+@@ -1787,6 +1787,10 @@
+       GOTO (fail);
+    }
+ 
++   if (!_mongoc_validate_db_name(opts->keyvault_db, -1, error)) {
++      GOTO(fail);
++   }
++
+    if (!opts->kms_providers) {
+       bson_set_error (
+          error, MONGOC_ERROR_CLIENT, 
MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required");
+@@ -1918,6 +1922,10 @@
+       GOTO (fail);
+    }
+ 
++   if (!_mongoc_validate_db_name(opts->keyvault_db, -1, error)) {
++      GOTO(fail);
++   }
++
+    if (!opts->kms_providers) {
+       bson_set_error (
+          error, MONGOC_ERROR_CLIENT, 
MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required");
+@@ -2027,6 +2035,10 @@
+       goto fail;
+    }
+ 
++   if (!_mongoc_validate_db_name(opts->keyvault_db, -1, error)) {
++      goto fail;
++   }
++
+    if (!opts->kms_providers) {
+       bson_set_error (
+          error, MONGOC_ERROR_CLIENT, 
MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required");
+--- a/src/libmongoc/src/mongoc/mongoc-client.c
++++ b/src/libmongoc/src/mongoc/mongoc-client.c
+@@ -1407,6 +1407,10 @@
+       prefix = "fs";
+    }
+ 
++   if (!_mongoc_validate_db_name(db, -1, error)) {
++      return NULL;
++   }
++
+    return _mongoc_gridfs_new (client, db, prefix, error);
+ }
+ 
+--- a/src/libmongoc/src/mongoc/mongoc-cmd.c
++++ b/src/libmongoc/src/mongoc/mongoc-cmd.c
+@@ -730,6 +730,13 @@
+    BSON_ASSERT (!parts->assembled.command);
+    BSON_ASSERT (bson_empty (&parts->assembled_body));
+ 
++   // The database name is sent as "$db" for OP_MSG or as "<db>.$cmd" for 
OP_QUERY.
++   // Reject a name the driver cannot forward faithfully, rather than 
silently targeting a different database.
++   BSON_ASSERT(parts->assembled.db_name);
++   if (!_mongoc_validate_db_name(parts->assembled.db_name, -1, error)) {
++      GOTO(done);
++   }
++
+    /* begin with raw flags/cmd as assembled flags/cmd, might change below */
+    parts->assembled.command = parts->body;
+    /* unused in OP_MSG: */
+--- a/src/libmongoc/src/mongoc/mongoc-collection.c
++++ b/src/libmongoc/src/mongoc/mongoc-collection.c
+@@ -288,6 +288,7 @@
+ {
+    return _mongoc_aggregate (collection->client,
+                              collection->ns,
++                             collection->db,
+                              flags,
+                              pipeline,
+                              opts,
+@@ -440,8 +441,12 @@
+ 
+    bson_clear (&collection->gle);
+ 
+-   return _mongoc_cursor_find_new (
++   mongoc_cursor_t *const cursor = _mongoc_cursor_find_new(
+       collection->client, collection->ns, filter, opts, read_prefs, 
collection->read_prefs, collection->read_concern);
++
++   _mongoc_cursor_check_db_name(cursor, collection->db);
++
++   return cursor;
+ }
+ 
+ 
+@@ -1621,6 +1626,7 @@
+    /* No read preference. Index Enumeration Spec: "run listIndexes on the
+     * primary node in replicaSet mode". */
+    cursor = _mongoc_cursor_cmd_new (collection->client, collection->ns, &cmd, 
opts, NULL, NULL, NULL);
++   _mongoc_cursor_check_db_name(cursor, collection->db);
+ 
+    if (!mongoc_cursor_error (cursor, &error)) {
+       _mongoc_cursor_prime (cursor);
+@@ -2899,6 +2905,11 @@
+       return false;
+    }
+ 
++   // The "to" field below is a joined namespace, which the server splits at 
the first ".".
++   if (new_db && !_mongoc_validate_db_name(new_db, -1, error)) {
++      return false;
++   }
++
+    newns = bson_strdup_printf ("%s.%s", new_db ? new_db : collection->db, 
new_name);
+ 
+    BSON_APPEND_UTF8 (&cmd, "renameCollection", collection->ns);
+--- a/src/libmongoc/src/mongoc/mongoc-cursor-private.h
++++ b/src/libmongoc/src/mongoc/mongoc-cursor-private.h
+@@ -165,6 +165,10 @@
+ _mongoc_n_return (mongoc_cursor_t *cursor);
+ void
+ _mongoc_set_cursor_ns (mongoc_cursor_t *cursor, const char *ns, uint32_t 
nslen);
++// Set an error on the cursor if `db` is not a valid database name.
++// Useful since `_mongoc_set_cursor_ns` does not know if a "." is in the db 
(invalid) or collection (valid).
++bool
++_mongoc_cursor_check_db_name(mongoc_cursor_t *cursor, const char *db);
+ bool
+ _mongoc_cursor_get_opt_bool (const mongoc_cursor_t *cursor, const char 
*option);
+ void
+--- a/src/libmongoc/src/mongoc/mongoc-cursor.c
++++ b/src/libmongoc/src/mongoc/mongoc-cursor.c
+@@ -174,6 +174,21 @@
+ }
+ 
+ 
++bool
++_mongoc_cursor_check_db_name(mongoc_cursor_t *cursor, const char *db)
++{
++   BSON_ASSERT_PARAM(cursor);
++   BSON_ASSERT_PARAM(db);
++
++   // Preserve an error already recorded by cursor construction.
++   if (CURSOR_FAILED(cursor)) {
++      return false;
++   }
++
++   return _mongoc_validate_db_name(db, -1, &cursor->error);
++}
++
++
+ /* return first key beginning with $, or NULL. precondition: bson is valid. */
+ static const char *
+ _first_dollar_field (const bson_t *bson)
+--- a/src/libmongoc/src/mongoc/mongoc-database.c
++++ b/src/libmongoc/src/mongoc/mongoc-database.c
+@@ -137,6 +137,7 @@
+ {
+    return _mongoc_aggregate (db->client,
+                              db->name,
++                             db->name,
+                              MONGOC_QUERY_NONE,
+                              pipeline,
+                              opts,
+@@ -755,6 +756,7 @@
+    /* Enumerate Collections Spec: "run listCollections on the primary node in
+     * replicaset mode" */
+    cursor = _mongoc_cursor_cmd_new (database->client, database->name, &cmd, 
opts, NULL, NULL, NULL);
++   _mongoc_cursor_check_db_name(cursor, database->name);
+    if (cursor->error.domain == 0) {
+       _mongoc_cursor_prime (cursor);
+    }
+--- a/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c
++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c
+@@ -25,6 +25,7 @@
+ #include <mongoc/mongoc-stream-gridfs-download-private.h>
+ #include <mongoc/mongoc-stream-gridfs-upload-private.h>
+ #include <mongoc/mongoc-stream-private.h>
++#include <mongoc/mongoc-util-private.h>
+ #include <mongoc/mongoc-write-concern-private.h>
+ 
+ /*--------------------------------------------------------------------------
+@@ -94,6 +95,21 @@
+       return NULL;
+    }
+ 
++   // Validate `bucketName` from the BSON options since it may contain an 
embedded NUL.
++   {
++      bson_iter_t iter;
++
++      if (opts && bson_iter_init_find(&iter, opts, "bucketName") && 
BSON_ITER_HOLDS_UTF8(&iter)) {
++         uint32_t bucket_name_len;
++         const char *const bucket_name = bson_iter_utf8(&iter, 
&bucket_name_len);
++
++         if (!_mongoc_validate_collection_name(bucket_name, bucket_name_len, 
error)) {
++            _mongoc_gridfs_bucket_opts_cleanup(&gridfs_opts);
++            return NULL;
++         }
++      }
++   }
++
+    /* Initialize the bucket fields */
+    if (strlen (gridfs_opts.bucketName) + strlen (".chunks") + 1 > sizeof 
(buf)) {
+       bson_set_error (error,
+--- a/src/libmongoc/src/mongoc/mongoc-uri.c
++++ b/src/libmongoc/src/mongoc/mongoc-uri.c
+@@ -1296,6 +1296,15 @@
+       source = bson_iter_utf8 (&iter, NULL);
+    }
+ 
++   // Validate `authSource`:
++   {
++      bson_error_t validate_error;
++      if (source && !_mongoc_validate_db_name(source, -1, &validate_error)) {
++         MONGOC_URI_ERROR(error, "%s", validate_error.message);
++         return false;
++      }
++   }
++
+    if (mongoc_uri_get_auth_mechanism (uri)) {
+       /* authSource with GSSAPI or X509 should always be external */
+       if (!strcasecmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI") ||
+@@ -1937,6 +1946,12 @@
+       return false;
+    }
+ 
++   // Match the validation applied to a database name parsed from the URI 
path. `_parse_path` rejects a larger set of
++   // characters; a "." is rejected here because it would silently retarget 
the namespace.
++   if (!_mongoc_validate_db_name_or_log(database)) {
++      return false;
++   }
++
+    if (uri->database) {
+       bson_free (uri->database);
+    }
+@@ -1992,6 +2007,11 @@
+       return false;
+    }
+ 
++   // `authSource` is a database name. See `mongoc_uri_finalize_auth`.
++   if (!_mongoc_validate_db_name_or_log(value)) {
++      return false;
++   }
++
+    mongoc_uri_bson_append_or_replace_key (&uri->credentials, 
MONGOC_URI_AUTHSOURCE, value);
+ 
+    return true;
+--- a/src/libmongoc/src/mongoc/mongoc-util-private.h
++++ b/src/libmongoc/src/mongoc/mongoc-util-private.h
+@@ -98,6 +98,40 @@
+ bool
+ _mongoc_validate_replace (const bson_t *insert, bson_validate_flags_t vflags, 
bson_error_t *error);
+ 
++/**
++ * @brief Validate a database name argument.
++ *
++ * Rejects a "." (the driver joins `db + "." + collection` into a namespace 
that the server splits at the first ".",
++ * so the server would never see the intended database name) and an embedded 
NUL byte (the name is truncated by the
++ * C string and wire protocol cstring encodings). Other characters prohibited 
by the MongoDB manual are forwarded
++ * faithfully and are left for the server to reject.
++ *
++ * @param db The database name to validate.
++ * @param db_len The length of @p db in bytes, or a negative value if @p db 
is NUL-terminated.
++ * @param error Optional out-parameter for the error.
++ * @return true if @p db is a usable database name.
++ */
++bool
++_mongoc_validate_db_name(const char *db, int64_t db_len, bson_error_t *error);
++
++/**
++ * @brief Validate a collection name argument.
++ *
++ * Rejects an embedded NUL byte. A "." is permitted in a collection name.
++ *
++ * @param collection The collection name to validate.
++ * @param collection_len The length of @p collection in bytes, or a negative 
value if @p collection is NUL-terminated.
++ * @param error Optional out-parameter for the error.
++ * @return true if @p collection is a usable collection name.
++ */
++bool
++_mongoc_validate_collection_name(const char *collection, int64_t 
collection_len, bson_error_t *error);
++
++// _mongoc_validate_db_name_or_log validates a NUL-terminated database name, 
logging the error at the ERROR level if
++// invalid. For use by APIs that have no `bson_error_t` out-parameter.
++bool
++_mongoc_validate_db_name_or_log(const char *db);
++
+ bool
+ _mongoc_validate_update (const bson_t *update, bson_validate_flags_t vflags, 
bson_error_t *error);
+ 
+--- a/src/libmongoc/src/mongoc/mongoc-util.c
++++ b/src/libmongoc/src/mongoc/mongoc-util.c
+@@ -18,6 +18,7 @@
+ #define _CRT_RAND_S
+ #endif
+ 
++#include <limits.h>
+ #include <string.h>
+ 
+ #include <bson/bson.h>
+@@ -464,6 +465,81 @@
+    }
+ 
+    return true;
++}
++
++
++// _validate_name checks a database or collection name argument for 
characters the driver's own encoding cannot
++// faithfully forward to the server. See `_mongoc_validate_db_name` and 
`_mongoc_validate_collection_name`.
++static bool
++_validate_name(const char *name, int64_t name_len, bool is_db, bson_error_t 
*error)
++{
++   BSON_ASSERT_PARAM(name);
++   BSON_OPTIONAL_PARAM(error);
++
++   size_t len = 0;
++   if (name_len < 0) {
++      len = strlen(name);
++   } else if (mcommon_in_range_signed(size_t, name_len)) {
++      len = (size_t)name_len;
++   } else {
++      bson_set_error(error,
++                     MONGOC_ERROR_NAMESPACE,
++                     MONGOC_ERROR_NAMESPACE_INVALID,
++                     "%s name invalid: too large",
++                     is_db ? "database" : "collection");
++      return false;
++   }
++
++   if (memchr(name, '\0', len)) {
++      bson_set_error(error,
++                     MONGOC_ERROR_NAMESPACE,
++                     MONGOC_ERROR_NAMESPACE_INVALID,
++                     "%s name invalid: contains a NUL byte",
++                     is_db ? "database" : "collection");
++      return false;
++   }
++
++   if (is_db && memchr(name, '.', len)) {
++      const int print_len = mcommon_in_range_signed(int, len) ? (int)len : 
INT_MAX;
++
++      bson_set_error(error,
++                     MONGOC_ERROR_NAMESPACE,
++                     MONGOC_ERROR_NAMESPACE_INVALID,
++                     "database name \"%.*s\" invalid: contains \".\"",
++                     print_len,
++                     name);
++      return false;
++   }
++
++   return true;
++}
++
++
++bool
++_mongoc_validate_db_name(const char *db, int64_t db_len, bson_error_t *error)
++{
++   return _validate_name(db, db_len, true /* is_db */, error);
++}
++
++
++bool
++_mongoc_validate_collection_name(const char *collection, int64_t 
collection_len, bson_error_t *error)
++{
++   return _validate_name(collection, collection_len, false /* is_db */, 
error);
++}
++
++
++bool
++_mongoc_validate_db_name_or_log(const char *db)
++{
++   bson_error_t error;
++
++   if (!_mongoc_validate_db_name(db, -1, &error)) {
++      MONGOC_ERROR("%s", error.message);
++      return false;
++   }
++
++   return true;
+ }
+ 
+ 
diff -Nru mongo-c-driver-1.30.4/debian/patches/series 
mongo-c-driver-1.30.4/debian/patches/series
--- mongo-c-driver-1.30.4/debian/patches/series 2026-04-27 11:48:27.000000000 
-0400
+++ mongo-c-driver-1.30.4/debian/patches/series 2026-08-29 11:06:27.000000000 
-0400
@@ -7,3 +7,4 @@
 0006_CVE-2025-14911.patch
 0007_CVE-2025-14911.patch
 0008_CVE-2026-6691.patch
+0009_CVE-2026-81524.patch

Reply via email to