MongoDB Symbol-Type Authorization Bypass (CVE-2026-18690): Beperkte gebruiker bereikt systeemcollecties

Wanneer de naam wordt verzonden als een BSON-symbool in plaats van een string, stort de authorisatie-parse stilzwijgend in tot een namespace op databaseniveau, terwijl de uitvoering nog steeds de werkelijke collectie resolveert. De twee helften van de server zijn het niet eens over welk object wordt aangeraakt, waardoor een gebruiker met beperkte rechten toegang krijgt tot een beschermde systeemcollectie die door de authorisatiecontrole normaal gesproken zou worden geweigerd. We hebben de exacte vector gereconstrueerd op basis van de éénregelige source-fix van MongoDB en deze gereproduceerd in MongoDB 8.0.28; de fix is geverifieerd in versie 8.0.29.

Overzicht van de kwetsbaarheden

CVE-2026-18690

  • CWE: CWE-863 Incorrect Authorization
  • Beschrijving: Een collectienaam van het type 'symbool' omzeilt de authorisatiecontrole op beschermde systeemcollecties.
  • CVSS 3.1 score: 8.1 (CVSS 4.0: 7.2)
  • Vector: C:N/I:H/A:H — impact op integriteit en beschikbaarheid, niet op vertrouwelijkheid.

CVE-2026-18691 (Hoogste score)

  • CVSS 4.0 score: 9.0 Critical (3.1: 8.8)
  • CWE: CWE-757
  • Beschrijving: Een downgrade van het authenticatiemechanisme binnen een cluster, wat de interne inloggegevens van de replica set kan blootstellen.

Threat Model (Bedreigingsmodel)

  • Voorwaarde (PR:L): De aanvaller beschikt al over een geldig, beperkt MongoDB-account (een database-scoped rol). Dit is sprake van privilege escalation binnen een geauthenticeerde implementatie, niet van een ongeauthenticeerde bug die via het internet toegankelijk is.
  • Exploitatie: Er is geen publiek bewijs van exploitatie in het wild; op het moment van schrijven staat deze niet op de CISA KEV-lijst.
  • Bron: MongoDB Inc. (CNA); root cause herleid naar SERVER-130481.

Ben ik kwetsbaar?

Je bent kwetsbaar als:

Je gebruikmaakt van MongoDB Server versies vóór 7.0.40 / 8.0.29 / 8.3.8 (de 8.3-lijn bevat ook de -18692 timeseries bug) en er minstens één gebruiker is met een beperkte, database-scoped rol in plaats van volledige admin-rechten.

Je bent niet kwetsbaar als:

Alle accounts volledige administratoren zijn (er is niets om naar te escaleren) of als de installatie al draait op 7.0.40+ / 8.0.29+ / 8.3.8+.

Controleren

Gebruik het volgende commando om de versie te controleren: mongosh "$URI" --quiet --eval 'db.version()' — vergelijk dit met 7.0.40 / 8.0.29 / 8.3.8. Lokaal kan dit via mongod --version.

Oplossing

Upgrade naar de vaste patch-release voor jouw versie (7.0.40, 8.0.29 of 8.3.8). Er is geen workaround via configuratie; de parser-fix is de enige oplossing.

Het patroon: Twee parses, één namespace

MongoDB handhaaft rolgebaseerde toegangscontrole op elk commando. Een commando benoemt de collectie waarop het opereert — bijvoorbeeld { convertToCapped: "orders", size: 4096 } — en de server extraheert die namespace om twee aparte dingen te bepalen:

  1. Mag deze gebruiker dit doen? (Authorisatie)
  2. Wat moet ik precies doen? (Uitvoering)

Het beveiligingsmodel werkt alleen als beide delen dezelfde namespace extraheren uit hetzelfde commando. Wanneer ze uiteenlopen, beantwoordt de authorisatiecontrole een vraag over een ander object dan het object dat het commando daadwerkelijk zal raken.

Dit is exact hetzelfde patroon als bij de Portainer-authorisatiebypass: daar bereikte een verzoek dat door de proxy niet was gecanonicaliseerd de Docker-daemon buiten de controle om. Hier is de splitsing subtieler: deze vindt plaats binnen één enkel MongoDB-proces, in de regels die de collectienaam uit het BSON van een commando lezen.

Grondoorzaak: Een non-string namespace valt terug naar de database

De extractie van de namespace voor een commando bevindt zich in CommandHelpers::parseNsFromCommand. De kwetsbare versie leest het eerste veld van het commando — de collectienaam — en als dit geen String is, stopt hij en retourneert hij een namespace die alleen de database bevat.

Kwetsbare code (MongoDB 8.0.28):

// src/mongo/db/commands.cpp
NamespaceString CommandHelpers::parseNsFromCommand(const DatabaseName& dbName,
const BSONObj& cmdObj) {
    BSONElement first = cmdObj.firstElement();
    if (first.type() != mongo::String)          // een BSON 'symbol' is geen String...
        return NamespaceString(dbName);         // ...dus dit retourneert een DATABASE-ONLY namespace
    return NamespaceStringUtil::deserialize(dbName, first.valueStringData());
}

Een BSON-symbool (type 0x0E) is een verouderd string-achtig type: op de wire wordt de tekst exact hetzelfde opgeslagen als een string, maar de type-byte is anders. Wanneer de collectienaam dus als symbool arriveert, is de test first.type() != String waar, en retourneert de functie een database-only namespace.

De volgende helper bepaalt vervolgens welk resource geautoriseerd moet worden:

ResourcePattern CommandHelpers::resourcePatternForNamespace(const NamespaceString& ns) {
    if (!NamespaceString::validCollectionComponent(ns))     // geen collectieonderdeel...
        return ResourcePattern::forDatabaseName(ns.dbName()); // ...autoriseer de gehele DATABASE
    return ResourcePattern::forExactNamespace(ns);
}

Omdat er geen collectiecomponent is, wordt de authorisatie geëvalueerd tegen de database-resource — een brede permissie die een gewone readWrite-gebruiker al heeft — in plaats van tegen de specifieke, beschermde system.* collectie. De uitvoering leest echter het symbool met valueStringData() (wat identiek werkt voor strings en symbolen) en opereert op de werkelijke collectie.

De fix in 8.0.29: MongoDB heeft één clausule toegevoegd:

// MongoDB 8.0.29 (fixed) — SERVER-130481
-   if (first.type() != mongo::String)
+   if (first.type() != mongo::String && first.type() != mongo::Symbol)
    return NamespaceString(dbName);

Nu wordt een symbool op dezelfde manier gedeserialiseerd als een string, waardoor de authorisatie de werkelijke target ziet en het verzoek weigert.

Reproductie in MongoDB 8.0.28

De bug treedt op bij elk commando waarvan de vereiste bevoegdheid door een database-scoped gebruiker op databaseniveau wordt beheerd. convertToCapped is hiervoor een duidelijk voorbeeld: readWrite verleent dit op de database, maar het commando mag niet worden uitgevoerd op systeemcollecties.

We hebben een MongoDB 8.0.28 omgeving opgezet met authenticatie en een database-scoped gebruiker, appuser (readWrite alleen op appdb). De doelwitten zijn de beschermde collecties system.profile en system.views.

Als we als appuser de collectienaam eerst als normale string verzenden en daarna als BSON-symbool, zien we het volgende:

MongoDB 8.0.28 (KWETSBAAR)

  • convertToCapped system.views
  • string namespace → Unauthorized (geweigerd bij authorisatie — correct)
  • symbol namespace → BadValue (PASSY door authorisatie; faalt pas bij uitvoering)
  • convertToCapped system.profile
  • string namespace → Unauthorized
  • symbol namespace → BadValue $\leftarrow$ AUTHORISATIE OMZEILD

De BadValue fout is hier cruciaal: dit is geen authorisatiefout. Bij een string stopt MongoDB bij Unauthorized. Bij een symbool bereikt het verzoek de eigen uitvoeringslogica van convertToCapped, die vervolgens weigert omdat een view (of de profiler-collectie) niet 'capped' kan worden. De beveiligingsgrens — de authorisatie — is echter al overschreden.

Op een systeemcollectie die wél gecapped kan worden, zou de actie "drop-and-recreate" plaatsvinden, wat precies is wat het security advisory beschrijft en waarom de vector score I:H/A:H is.

MongoDB 8.0.29 (GEFIXT)

  • convertToCapped system.views
  • string namespace → Unauthorized
  • symbol namespace → Unauthorized (bypass gesloten)
  • convertToCapped system.profile
  • string namespace → Unauthorized
  • symbol namespace → Unauthorized

De overige kwetsbaarheden in dit pakket

Naast CVE-2026-18690 bevatten de releases fixes voor drie andere Server CVE's:

  • CVE-2026-18712 (8.1): Eveneens CWE-863 Incorrect Authorization. Een gebruiker met privileges op één Queryable Encryption-collectie kan, door onvoldoende validatie van interne metadata, data in een andere collectie wijzigen of vernietigen.
  • CVE-2026-18691 (CVSS 4.0 9.0): Een downgrade van het authenticatiemechanisme binnen het cluster (CWE-757). Een partij met netwerktoegang kan de onderhandeling tussen replica-set leden beïnvloeden, wat de gedeelde interne inloggegevens van het cluster kan blootstellen. Dit vereist specifieke omstandigheden en netwerknabijheid; indien succesvol geeft dit toegang als internal-superuser.
  • CVE-2026-18692 (8.8): Een use-after-free (CWE-416) in de lifecycle van timeseries buckets, bereikbaar door een geauthenticeerde gebruiker met schrijfrechten. Dit kan leiden tot een crash of potentieel code execution. Deze bug beïnvloedt alleen de 8.3-lijn (8.3.0–8.3.7).

Eén patroon, twee producten

Beide onderzochte bugs vertonen hetzelfde patroon waarbij de authorisatielaag en de uitvoeringslaag het oneens zijn over welk object een verzoek target:

  • Portainer (CVE-2026-44848): Een verzoekvorm die de proxy nooit had gemodelleerd, bereikte de Docker-daemon ongecontroleerd → host RCE.
  • MongoDB (CVE-2026-18690): De huidige analyse.

MongoDB-instanties vinden op uw netwerk

Geen van deze bugs werkt zonder authenticatie; ze vereisen een geldig, zij het beperkt, account. Toch is het essentieel om in kaart te brengen of er kwetsbare MongoDB-instanties aanwezig zijn:

  1. Scan op poort 27017 (standaard).
  2. Bevestig dat het MongoDB is via de wire-protocol handshake.
  3. Authenticeer om de versie te lezen (db.version()), aangezien deze niet aan ongeauthenticeerde cliënten wordt verstrekt.

$ mongosh "mongodb://user:[email protected]:27017/?authSource=admin" --quiet --eval 'db.version()'

Een MongoDB-instantie die bereikbaar is vanuit een onbetrouwbaar netwerk is op zichzelf al een bevinding, ongeacht de versie.

Herstelmaatregelen

  • Upgrade: Update naar patch-release 7.0.40, 8.0.29 of 8.3.8. Er is geen configuratie-mitigatie voor 18690.
  • Beperk de 'blast radius': Behandel elk niet-admin account als een potentieel risico. Inventariseer wie database-scoped rollen heeft; juist deze beperkte rollen vormen de precondition voor de bypass.
  • Netwerkbeveiliging: Haal MongoDB weg van onbetrouwbare netwerken. Bind aan private interfaces, vereis TLS en exposeer poort 27017 niet aan het internet. Bescherm specifiek het interne communicatiekanaal tussen cluster-leden (voor CVE-2026-18691).
  • Herken het patroon: Wees alert op situaties waarin een systeem een input parseert voor authorisatie en deze vervolgens opnieuw parseert voor uitvoering. Vraag je af of deze twee parses kunnen worden gedwongen om tot verschillende resultaten te komen via alternatieve coderingen, verouderde types of niet-canonieke vormen.

Triage-notities

Remote reconnaissance bewijst:

  • Dat er een MongoDB-instantie bestaat en of deze netwerk-exposed is.
  • De versie kan alleen worden vastgesteld via een geauthenticeerde verbinding.

Het kan niet bewijzen:

  • Of er non-admin gebruikers zijn met een database-scoped rol. Deze informatie moet intern worden verzameld.

Benodigde bewijslast voor audit:

  • db.version()
  • Output van db.getUsers() / roltoewijzingen per database.
  • Controle of applicaties verbinden met een scoped rol in plaats van een admin-rol (wat bij bijna alle applicaties het geval is).

Drempel voor escalatie: Elke implementatie onder 7.0.40 / 8.0.29 / 8.3.8 met minstens één database-scoped account. Deze combinatie maakt een directe authorisatiebypass van beperkte gebruiker naar systeemcollectie mogelijk via CVE-2026-18690.

Voorbeeld van bevinding: "De MongoDB-implementatie bevindt zich onder de fix-lijn van augustus 2026 (7.0.40 / 8.0.29 / 8.3.8) en maakt gebruik van database-scoped rollen. Dit stelt een beperkte gebruiker in staat om de authorisatie op beschermde systeemcollecties te omzeilen via een BSON symbol-type namespace (CVE-2026-18690). Upgrade naar de vaste patch-release."

Bronnen

  • NVD: CVE-2026-18690 (Incorrect Authorization, system collections)
  • NVD: CVE-2026-18691 (intra-cluster auth downgrade, CVSS 4.0 9.0)
  • NVD: CVE-2026-18692 (timeseries use-after-free, 8.3 line)
  • NVD: CVE-2026-18712 (Queryable Encryption cross-collection)
  • MongoDB JIRA: SERVER-130481 (parseNsFromCommand symbol type)
  • MongoDB source: commands.cpp (r8.0.29, fixed parseNsFromCommand)
  • MongoDB: system collections reference