Authorize compactStructuredEncryptionData and cleanupStructuredEncryptionData at database scope

XMLWordPrintableJSON

    • Server Security
    • ALL
    • v9.0, v8.3, v8.2, v8.0, v7.0
    • Server Security 2026-08-28
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Security Context

      See SECBUG-1276 for problem description, security impact, preconditions, reproduction steps, and severity rationale.

      Root Cause

      doCheckAuthorization (fle2_compact_cmd.cpp:355-363) authorizes exactly one resource and action:

      // fle2_compact_cmd.cpp:355-363 (master)
      void doCheckAuthorization(OperationContext* opCtx) const final {
          auto* as = AuthorizationSession::get(opCtx->getClient());
          uassert(ErrorCodes::Unauthorized,
                  "Not authorized to compact structured encryption data",
                  as->isAuthorizedForActionsOnResource(
                      ResourcePattern::forExactNamespace(request().getNamespace()),
                      ActionType::compactStructuredEncryptionData));
      } 

      This check authorizes only the EDC namespace. Execution then derives mutated namespaces from the EDC's stored encryptedFieldConfig via EncryptedStateCollectionsNamespaces::createFromDataCollection():

      // fle2_compact.cpp:329-344 (master) — names copied verbatim, no ownership constraint
      namespaces.escNss = NamespaceStringUtil::deserialize(
          dbName, cfg.getEscCollection().value_or_eval([&f]() { return f("state"sv); }));
      namespaces.ecocNss = NamespaceStringUtil::deserialize(
          dbName, cfg.getEcocCollection().value_or_eval([&f]() { return f("compaction"sv); }));
      // ...
      namespaces.ecocRenameNss = NamespaceStringUtil::deserialize(
          dbName, std::string{namespaces.ecocNss.coll()}.append(".compact"));
      namespaces.ecocLockNss = NamespaceStringUtil::deserialize(
          dbName, std::string{namespaces.ecocNss.coll()}.append(".lock")); 

      If ecocCollection in the stored config is set to a victim collection name V, then ecocRenameNss = V.compact and ecocLockNss = V.lock. Execution then performs the following catalog mutations with no additional authorization checks:

      • renameCollection(ecocNss → ecocRenameNss) — victim V is renamed to V.compact
      • dropCollection(ecocRenameNss) — V.compact (the renamed victim) is permanently deleted
      • createCollection(ecocNss) — a new empty collection is created at V (data destroyed)
      • DBDirectClient delete/insert on escNss — bulk writes into whatever escNss names.

      The internal primitives validateAndRunRenameCollection() and dropCollection() do not call AuthorizationSession; they perform no authorization on the target namespace. The lock acquisition immediately before these operations uses the derived (attacker-controlled) namespaces, not the EDC namespace that was authorized.

      If escCollection in the stored config is set to a victim collection name, then compaction also performs deletions on the victim's ESC collection, which breaks the correctness of the victim's encrypted queries.

      Attack Preconditions

      The attacker needs:

      1. A MongoDB user account with the compactStructuredEncryptionData privilege scoped to a single EDC namespace in the target database (a minimal QE compaction service account).
      2. A mechanism to set the escCollection or ecocCollection name in the EDC's stored encryptedFieldConfig to the name of a victim collection. This can be achieved via: createCollection with arbitrary encryptedFields.

      Impact

      The attacker can permanently destroy another user's QE state collection data by causing compact/cleanup to remove documents from the victim's ESC, and to rename and drop the victim's ECOC.

      Proposed Fix

      Raise the authorization scope level required by the "compactStructuredEncryptionData" and "cleanupStructuredEncryptionData" commands to be at database scope rather than exact-namespace scope.

            Assignee:
            Erwin Pe
            Reporter:
            Erwin Pe
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: