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