Abstracte technische illustratie op een donker marineblauw vlak: een gloeiende invoerpoort aan de linkerwand van een doorschijnende doos laat een enkele dunne bleke lijn door die geen badge en geen sleutel draagt. Binnen in de doos komt de lijn bij een stapel kleine afgeronde panelen en splitst zich in een korte rij hoekige, commando-achtige streken die naar beneden lopen naar een lager compartiment met een cluster gloeiende sleutelvormige tokens. Een tweede, gesloten poort met een bleekblauwe omtrek staat naast de invoerpoort. Geen tekst, geen mensen, geen organisatielogo's.
AI Safety Incidents

Een niet-geauthenticeerde POST naar de Management API van Bifrost startte een commando als de gateway-gebruiker

Auteur

Magnus Corvin

Publicatiedatum

Nieuwste modellen · 20Bekijk alle modellen →
Benchmarks: Artificial Analysis · dagelijks bijgewerkt
Terug naar alle berichten

Op 14 september 2026 publiceerde JFrog Security Research CVE-2026-90898, een fout waardoor commando's kunnen worden uitgevoerd in Bifrost — de opensource-AI-gateway die door Maxim wordt onderhouden — en kende er 9,8 van de 10 punten aan toe. De aanval bestond uit één HTTP-verzoek. Een niet-geauthenticeerde POST /api/mcp/client registreert een stdio-MCP-client, die Bifrost leest als een programmanaam plus een argumentenlijst en onmiddellijk start, vóór enige MCP-handshake, als de gebruiker die de gateway draait; op de officiële image is die gebruiker appuser. Een gateway is ook de plek waar de provider-sleutels en virtuele sleutels van een operator staan, dus een proces dat daar draait, kan bij inloggegevens komen. Wat het verzoek anoniem maakte, was een meegeleverde standaardinstelling: governance.auth_config.is_enabled is false, en, in JFrog's bewoordingen, "auth uit betekent dat elke aanroeper een lokale admin is." Geen aangehaalde bron meldt dat de fout ooit is misbruikt. De eigen bronnen van het record, de ernstgraad en de betrouwbaarheidsbeoordeling staan in het AI-incidentarchief, naast de andere gedocumenteerde AI-gateway- en MCP-kwetsbaarheden van het afgelopen jaar.

Bifrost is één enkele dienst die zich bevindt tussen een applicatie en de taalmodellen die deze aanroept. De repository beschrijft het als een opensource-gateway met Apache-2.0-licentie die "de toegang tot meer dan 23 providers ... verenigt via één OpenAI-compatibele API", met onder meer MCP-proxying, virtuele sleutels, budgetten en loadbalancing per provider als functies, en op 28 oktober 2026 had het ongeveer 9.150 GitHub-sterren. Die combinatie is precies de reden waarom een shell op deze specifieke host een kritieke score verdient: het proces dat de verzoeken routeert, is ook het proces dat de inloggegevens bezit voor elke upstream waarnaar het routeert. The Hacker News, dat de kwetsbaarheid op 22 september meldde, verwoordde de consequentie onomwonden: omdat de gateway API-sleutels opslaat voor elke aangesloten provider, geeft het uitvoeren van commando's op het gatewayproces de aanvaller toegang tot die inloggegevens.

De hele aanval was één enkele POST

Het advies van JFrog, gepubliceerd onder referentie JFSA-2026-001686326, beschrijft een endpoint dat bestaat om een beheerder een MCP-server te laten toevoegen. Een stdio-client in de MCP-specificatie is geen URL; het is een commando met de bijbehorende argumenten, dat het hostprogramma wordt geacht te starten. Bifrost accepteert die configuratie via de management-API en start het programma zodra de client wordt toegevoegd. Er is geen capability-onderhandeling, geen controle van de serveridentiteit en geen handshake die eerst moet slagen — het advies is expliciet dat de handshake niet is wat het proces start.

De proof of concept in het advies is een korte JSON-body die naar een gateway wordt gepost, waarbij authenticatie op de standaardwaarde is gelaten. Hiermee wordt een client geregistreerd waarvan het commando /bin/sh is en waarvan de argumenten een markerbestand schrijven, waarna het markerbestand wordt teruggelezen. JFrog voegt een operationeel detail toe dat van belang is tijdens incidentrespons: het HTTP-verzoek kan een timeout krijgen terwijl Bifrost wacht op een handshake die nooit komt, en een timeout in de logs betekent niet dat het commando niet is gestart. Het proces draait op dat moment al.

Het CVE-record, toegewezen door JFrog als CVE Numbering Authority, koppelt het defect aan CWE-306, ontbrekende authenticatie voor een kritieke functie, en CWE-284, onjuiste toegangscontrole, en noemt de twee bestanden die de handler en de bijbehorende middleware bevatten: transports/bifrost-http/handlers/mcp.go en transports/bifrost-http/handlers/middlewares.go. De getroffen module is github.com/maximhq/bifrost/transports, op Linux en macOS, voor elke versie onder 2.1.0.

De standaardwaarde die het verzoek anoniem maakte

Niets daarvan zou exploiteerbaar zijn zonder een tweede voorwaarde, en die tweede voorwaarde is de eigen standaardinstelling van het product. De middleware voor beheerauthenticatie van Bifrost wordt aangestuurd door governance.auth_config.is_enabled, dat standaard op false staat. Als die uit staat, behandelt de middleware elke aanroeper als lokale beheerder — de samenvatting van het advies zelf is dat authenticatie uit betekent dat elke aanroeper een lokale admin is — dus de controle die het verzoek had moeten tegenhouden, zat nooit in het pad.

De oplossing, pull request #6757, werd op 2 september 2026 in het project samengevoegd, twaalf dagen voordat de CVE werd gepubliceerd en zes dagen voordat de release die hem bevat uitkwam. De beschrijving ervan is ongewoon openhartig over de aard van het probleem: de pull request sluit twee primitieven voor niet-geauthenticeerde toegang in dezelfde registratie-API, niet één. De eerste is de stdio-client. De tweede is een http- of sse-MCP-client die op een loopback- of privénetwerkadres is gericht, wat de request een SSRF-primitief tegen interne diensten noemt, "inclusief het cloudmetadata-endpoint 169.254.169.254". Beide worden nu geweigerd met HTTP 403 wanneer het verzoek de handler bereikt zonder een echte credentialcontrole. Geauthenticeerde beheerders behouden beide mogelijkheden, en operators kunnen nog steeds stdio-clients via config.json inrichten.

Die tweede primitief komt niet voor in de CVE-tekst. Hij staat in de patch, en dat is de reden dat de oplossing een poort is in plaats van een verwijdering: de functie was nooit de bug. Het behandelen van een niet-geauthenticeerde aanroeper als beheerder was dat wel.

Waar de management-API daadwerkelijk op luisterde

Bereikbaarheid is het deel van de gegevens dat de bronnen het meest consistent beschrijven en het minst meten. Het advies van JFrog geeft als standaardwaarde voor de meegeleverde binary localhost:8080, waardoor een aanvaller tot de host zelf wordt beperkt. Het advies van hetzelfde team over de bijbehorende kwetsbaarheid stelt dat de officiële Docker-image in plaats daarvan aan 0.0.0.0 bindt, en The Hacker News herhaalt dit: de image maakt de beheer-API van buiten de container bereikbaar als de poort wordt gepubliceerd. De quickstart in Bifrosts eigen README voert "docker run -p 8080:8080 maximhq/bifrost" uit, en Docker's -p publiceert een containerpoort op elke hostinterface tenzij een adres wordt opgegeven. Het GitHub-advies over de kwetsbaarheid vermeldt dat het gemelde pad is geverifieerd tegen de gepubliceerde maximhq/bifrost:latest-image, waarbij een niet-geauthenticeerd verzoek /bin/sh startte en een marker schreef als appuser.

Wat geen enkele bron levert, is een getal. Er is geen telling van internetgerichte Bifrost-instanties, geen scanresultaat, geen telemetrie en geen slachtoffer. Het verslag bevat geen werkelijke schade, en dat ontbreken is een gegeven over de berichtgeving in plaats van een geruststelling — de kwetsbaarheidsklasse is alleen gevaarlijk waar twee voorwaarden samenvallen, een blootgestelde listener en een onaangeroerde standaardinstelling, en niemand heeft gepubliceerd hoe vaak dat het geval was.

Eén endpoint, twee fouten, één grondoorzaak

Acht dagen vóór het MCP-advies, op 6 september 2026, publiceerde hetzelfde onderzoeksteam CVE-2026-86242, een tweede niet-geauthenticeerde toegangsweg naar hetzelfde proces. Ontdekt door Or Peles en met een score van 8.1, misbruikt het POST /api/plugins: Bifrost accepteert een ingeschakelde aangepaste plug-in waarvan het pad een HTTP-URL is, de shared-object-loader behandelt een pad met http-voorvoegsel als een download, schrijft de body naar een tijdelijk .so-bestand en geeft dat bestand aan Go's plugin.Open. Als het laden slaagt, wordt onmiddellijk een optionele Init-functie uitgevoerd met de configuratie van de aanvaller, als de gateway-gebruiker.

De buildvariant bepaalt wat een aanvaller krijgt. Op de dynamisch gelinkte builds die het project documenteert voor aangepaste Go-plugins, wordt verwacht dat het laden slaagt, wat de advisory ongeauthenticeerde remote code execution noemt. Op de gepubliceerde statisch gelinkte Docker-image mislukt plugin.Open met "Dynamic loading not supported", dus hetzelfde verzoek degradeert naar server-side request forgery. Een laadbare plugin moet ook overeenkomen met de Go-versie, het besturingssysteem, de architectuur en de linkage van de host, wat een echte beperking is en niet slechts een formaliteit. De fix is transports/v2.0.0, via pull request #5763, en het getroffen bereik is alles daaronder.

De valkuil is de releasevolgorde. v2.0.0 lost het plug-inpad op en lost het MCP-pad niet op — The Hacker News zegt dat expliciet, en het MCP-advies van JFrog bevestigt dat v2.0.0 nog steeds de niet-geauthenticeerde stdio-registratie toestaat. Een beheerder die na het advies van 6 september snel patchte, was alleen al op dat punt nog steeds blootgesteld totdat transports/v2.1.0 op 8 september werd uitgebracht. Beide fouten komen in beide adviezen en in de pull request van de leverancier zelf neer op dezelfde zin: authenticatie uitgeschakeld is de standaard.

Wat de bronnen vaststellen, en wat ze niet vaststellen

Het mechanisme, het versiebereik, de oplossing en de erkenning stemmen overeen in het advies, het door JFrog toegewezen CVE-record, de eigen pull request en release notes van het project, en The Hacker News. Het resterende meningsverschil betreft de ernst, en dat is reëel.

De 9,8 is de score van JFrog als toewijzende CNA, en het is de score die NVD hanteert — het NVD-record vermeldt reefs@jfrog.com als de bron van de metriek en vanaf 28 oktober 2026 staat de vermelding nog steeds op de status "Awaiting Analysis", wat betekent dat NVD de vector van de toewijzende partij heeft gepubliceerd in plaats van zijn eigen analyse daarvan. De SSVC-beoordeling van de CISA-coördinator die aan hetzelfde record is gekoppeld, met tijdstempel 14 september 2026, luidt: exploitatie "none", automatiseerbaar "yes" en technische impact "total". Het EPSS-model van FIRST stelde de kans op exploitatie in de komende 30 dagen op 27 oktober 2026 op 2,3 procent, in het 83e percentiel van alle gescoorde CVE's, en noch deze CVE noch CVE-2026-86242 komt voor in de CISA Known Exploited Vulnerabilities-catalogus van 27 oktober 2026.

Daarentegen betwist Maxim de beoordeling. In een verklaring aan The Hacker News zei Akshay Deo, de chief technology officer en medeoprichter van het bedrijf, dat het praktische risico lager is dan de kritieke score suggereert, omdat misbruik vereist dat de beheerinterface bereikbaar is vanaf een niet-vertrouwd netwerk en dat de operator authenticatie niet heeft ingesteld; de standaard- en gedocumenteerde implementatie, zei hij, plaatst de gateway binnen een privénetwerk. The Hacker News meldt dat Maxim de kwetsbaarheid als van lage ernst beschouwt en samenwerkt met JFrog, dat de CVE heeft toegewezen, om de beoordeling te herzien. Die verklaring verschijnt in dat ene medium; er is geen tweede publicatie gevonden die Maxims standpunt citeert, en er was op 28 oktober 2026 nog geen herziening gepubliceerd — het CVE-record is voor het laatst bijgewerkt op 14 september en de NVD-vermelding op 18 september, beide nog steeds op 9,8.

Twee verdere hiaten verdienen het om benoemd te worden in plaats van gladgestreken. De GitHub-advisories van het project, gepubliceerd op 23 september 2026 en waarin de onderzoeker van JFrog als melder wordt genoemd, vermelden nog steeds 9,8 voor het MCP-probleem en 8,1 voor het plugin-probleem, zonder enig teken van de herziening die Maxim beschreef. En de getroffen bereiken in die advisories zijn geschreven tegen Go-moduleversies — lager dan 1.5.27 en lager dan 1.6.3 — in plaats van de release-tags van transports die de JFrog-advisories gebruiken, zodat een beheerder die het ene document naast het andere legt eerst twee nummeringsschema's met elkaar moet verzoenen voordat hij kan beslissen of een build getroffen is.

Rendered two-column card with the kicker 'BIFROST · CVE-2026-90898' and the title 'What the sources establish — and what they do not', subtitled 'Sources: JFrog JFSA-2026-001686326 (14 September 2026), the CVE record assigned by JFrog, NVD, FIRST EPSS, the CISA KEV catalogue, and the project's pull request 6757 and release tags.' The left column, headed 'ESTABLISHED' in blue, lists eight items: score 9.8 with the vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H supplied by the CNA; CWE-306 missing authentication with CWE-284 access control; unauthenticated POST /api/mcp/client starting a program as the gateway user; affected below transports 2.1.0 when management auth is disabled, the default; fixed in transports 2.1.0, PR 6757 merged 2 September, released 8 September 2026; CISA SSVC of 14 September 2026 with exploitation none, automatable yes, impact total; EPSS 2.3 percent at the 83rd percentile on 27 October 2026; and not in the CISA KEV catalogue dated 27 October 2026. The right column, headed 'NOT ESTABLISHED, OR CONTESTED' in amber, lists eight items: no exploitation reported, and the archive records real harm as false; no count of exposed or affected deployments in any cited source; severity contested, the vendor's CTO telling The Hacker News it is low; no published revision to the score as of 28 October 2026; NVD still Awaiting Analysis, so the 9.8 is the assigner's and not NVD's; affected ranges stated in two numbering schemes across the advisories; no detection or triage guidance in either advisory; and no evidence tying the flaw to any intrusion. A footer reads 'Card rendered by OrcaRouter'. The OrcaRouter logo is composited in the bottom-right corner.

Wat is er veranderd, en wat is operators opgedragen te doen?

De chronologie loopt achterstevoren vanaf de openbaarmaking, wat het minst intuïtieve deel van het dossier is. Pull request #6757 werd op 2 september 2026 samengevoegd. transports/v2.1.0, de release die het advies noemt als de eerste met de fix, werd op 8 september gepubliceerd — zes dagen voordat CVE-2026-90898 op 14 september werd gepubliceerd. De pluginfix van het project ging op dezelfde manier aan zijn eigen advies vooraf: transports/v2.0.0 werd op 26 augustus uitgebracht, elf dagen vóór de CVE van 6 september. Operators die releases volgen in plaats van feeds hadden de patches voordat ze de waarschuwingen hadden.

Wat de upgrade oplevert, is beperkt en specifiek. Op 2.1.0 en later retourneert een niet-geauthenticeerde stdio-registratie een 403 en wordt de opdracht niet gestart; geauthenticeerde beheerders behouden de mogelijkheid, en provisionering via config.json werkt nog steeds. De noodoplossing uit het advies voor iedereen die niet kan overstappen, is om governance.auth_config.is_enabled op true te zetten, sterke beheerdersreferenties te gebruiken en de beheerlistener buiten niet-vertrouwde netwerken te houden. De instructie van JFrog voor instanties die blootgesteld hebben gedraaid met authenticatie uitgeschakeld, is niet om onderzoek te doen en te hopen: behandel ze als gecompromitteerd en roteer virtuele sleutels en providerreferenties.

De versiearitmetiek is het onderdeel dat het meest waarschijnlijk verkeerd wordt gelezen. v2.0.0 verhelpt deze fout niet. De 1.6.x-reeks tot en met 1.6.11 bevat de oplossing ook niet, en de nieuwste tag uit de 1.6-serie van het project is transports/v1.6.11, gepubliceerd op 14 augustus 2026, zonder een 1.7-reeks in de repository per 28 oktober 2026 — dus er is geen gepatchte release binnen die serie, en een 1.6.x-operator moet overstappen naar 2.1.0 of later in plaats van te wachten op een backport. De huidige release-reeks ligt ruim voorbij dat punt: transports/v2.3.2 is gepubliceerd op 20 oktober 2026.

Rendered release-timeline card with the kicker 'BIFROST · RELEASE TIMELINE', the title 'The fix shipped six days before the advisory' and the subtitle 'Dates from the project's release tags and pull request metadata, the JFrog advisories and The Hacker News. Every date below is a single day.' A horizontal timeline carries seven dated markers: 26 Aug 2026, transports 2.0.0 published; 2 Sep 2026, PR 6757 merged; 6 Sep 2026, CVE-2026-86242 published, 8.1; 8 Sep 2026, transports 2.1.0, the fix; 14 Sep 2026, CVE-2026-90898 published, 9.8; 22 Sep 2026, vendor statement reported; 23 Sep 2026, GitHub advisories published. Below it, three bars show release lines: a hatched amber bar labelled '1.6.x line' reading 'affected — no patched release in the series; newest tag 1.6.11, 14 August 2026'; a bar labelled '2.0.0' split between a pale blue segment reading 'plugin flaw fixed' and a red segment reading 'MCP flaw still open'; and a solid blue bar labelled '2.1.0 and later' reading 'MCP fix — unauthenticated stdio registration returns 403'. A foot band headed 'THE PART THAT IS EASY TO GET WRONG' notes that 2.0.0 was the patched release on 6 September and did not close the MCP path, that for the two days before 2.1.0 an operator who patched on the day of the warning was still exposed, and that the 1.6.x series has no fixed release at all. A footer reads 'Card rendered by OrcaRouter'. The OrcaRouter logo is composited in the bottom-right corner.

Na de publicatie deden zich twee dingen voor die een verdediger kan benutten. De GitHub-beveiligingsadviezen van het project — GHSA-86gf-xh3g-rvxq voor de MCP-fout met kritieke ernst en GHSA-2qp8-4xgm-fw6g voor de pluginfout met hoge ernst — verschenen op 23 september 2026, waardoor de dependency- en adviesfeeds een tweede identificatie hebben om op te matchen. En op 13 oktober 2026 werd een detectiesjabloon voor CVE-2026-90898 samengevoegd in de openbare nuclei-templates-repository, wat betekent dat de controle op een ongeauthenticeerde registratiepoging nu iets is dat een scanpipeline kan uitvoeren in plaats van iets dat elk team zelf moet schrijven.

Abstract illustration on a dark navy field: a wide translucent slab representing a credential store, filled with evenly spaced glowing key-shaped tokens, stands behind a low wall. A narrow gateway aperture in the wall holds a fresh, brighter set of tokens, a blank card-shaped slip lies pushed aside on the ground in front of it, and a thin amber arc sweeps from the aperture around to the store. A second gateway aperture in the background remains closed and unlit. No text, no people, no organisation logos.

Wat nog openstaat, is de ernst, en of die al dan niet wordt beslecht, ligt bij de twee organisaties die er nog over in gesprek zijn. Maxims standpunt, zoals gemeld, is dat een 9,8 een kwetsbaarheid overdrijft die een blootgestelde listener en een niet-ingestelde standaardwaarde nodig heeft om ertoe te doen — een bewering die in principe toetsbaar is en in het openbaar niet is getoetst, omdat niemand heeft gepubliceerd hoeveel implementaties aan die twee voorwaarden voldeden. JFrogs standpunt is de score die het als CNA heeft toegekend, die nog steeds in het CVE-record en in NVD staat. Totdat een van hen een herziening publiceert, is de operationele interpretatie hoe dan ook dezelfde: de kwetsbaarheid is echt en is end-to-end geverifieerd op de gepubliceerde containerimage, de fix is vóór de waarschuwing uitgeleverd, de 1.6-serie heeft helemaal geen fix, en elk exemplaar dat draaide met authenticatie uitgeschakeld op een bereikbare listener moet als een inloggegevensincident worden behandeld in plaats van als een te plannen patch.