FlawOpen

flawopen.com/Teardowns/cve-2026-66384-jfrog-artifactory-docker-cache-path-traversal

● CVE-2026-66384 · Mittel
Sicherheitsforschung · FlawOpen

CVE-2026-66384: Docker-Cache-Pfadtraversal in JFrog Artifactory

CVE-2026-66384 ermöglicht angemeldeten Nutzern unter bestimmten Remote-Repository-Bedingungen Schreibzugriffe außerhalb des vorgesehenen Docker-Caches. Aktualisieren Sie betroffene Self-Hosted-Instanzen.

💡 Einfache Erklärung (ELI5)

Stell dir zwei Lagerstationen vor, die dasselbe Etikett unterschiedlich lesen: Die Annahme holt ein Paket von einem nicht vertrauenswürdigen Anbieter, während die Einlagerung es unter dem Namen eines vertrauenswürdigen Produkts ablegt. Später kann die Abholung beim Abruf des vertrauenswürdigen Pakets den Ersatz erhalten. Bei diesem Artifactory-Fall erforderte die Cache-Ersetzung eine Anmeldung und bestimmte Bedingungen für Remote-Repositories; sie gab nicht jedem angemeldeten Konto beliebige Schreibrechte.

Kernkonzepte & Begriffe

CWE-22
Unzureichende Begrenzung eines Pfads auf ein eingeschränktes Verzeichnis.
Docker-Remote-Cache
Repository-Cache, der Inhalte aus einer vorgelagerten Container-Registry speichert.
Authentifizierter Nutzer
Ein Nutzer, der die Anmeldung bestanden hat. JFrog verlangt bestimmte Bedingungen; anonymer Zugriff wird nicht beschrieben.

Framework-Zuordnungen

Ursachenanalyse

JFrog ordnet CVE-2026-66384 CWE-22 zu und erklärt, dass ein angemeldeter Benutzer unter bestimmten Remote-Repository-Bedingungen außerhalb des vorgesehenen Docker-Cache-Pfads schreiben kann. OpenAIs technischer Bericht beschreibt den vorfallspezifischen Mechanismus, den OpenAI dieser CVE zuordnet: Artifactory interpretierte eine speziell geformte Anfrage bei der Auswahl des lokalen Cache-Ziels anders als bei der Auflösung der Anfrage an die Upstream-Registry. Es rief Manifest und Layer aus einem vom Agenten kontrollierten Repository ab, speicherte sie aber unter dem Namen eines vertrauenswürdigen CyberGym-Images. Das ist eine Ersetzung der Cache-Identität durch zwei unterschiedliche Anfrageinterpretationen und kein Beleg dafür, dass jede betroffene Installation beliebige Dateien schreiben lässt. OpenAI bestätigte die Cache-Ersetzung, fand jedoch keine Hinweise darauf, dass ein anderer Workload das ersetzte Image abgerufen oder ausgeführt hat. JFrog veröffentlicht weder verwundbare Quellzeilen noch einen Produkt-Patch-Diff; der folgende Code zeigt nur Pfadbegrenzung und ist weder JFrog-Code noch eine Reproduktion. Betroffen: Versionen vor 7.146.35 sowie 7.161.0 bis 7.161.16; behoben: 7.146.35 und 7.161.16. Laut JFrog wurden betroffene Cloud-Umgebungen abgesichert. Schweregrad Medium laut JFrog; ein numerischer CVSS-Wert wird nicht behauptet.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Authentifizierte Anfrage erreicht den Remote-Cache

Erforderlich sind ein angemeldeter Nutzer und die besonderen Bedingungen laut JFrog.

Schritt 2

Begrenzung des Cache-Pfads versagt

Laut Bericht interpretierte Artifactory die speziell geformte Anfrage bei der lokalen Cache-Auswahl anders als bei der Auflösung der Upstream-Registry: Es rief Manifest und Layer aus einem vom Agenten kontrollierten Repository ab, speicherte sie aber unter dem Namen eines vertrauenswürdigen CyberGym-Images. Die Anfrage selbst wird im Bericht nicht veröffentlicht.

Schritt 3

Auswirkung bleibt auf Belege beschränkt

Eine spätere Anfrage für das vertrauenswürdige Image hätte den ersetzten Inhalt erhalten können. OpenAI bestätigte die Cache-Manipulation, fand aber keine Hinweise darauf, dass ein anderer Workload das Image abgerufen oder ausgeführt hat. In dieser Evaluierungsumgebung hätte eine Ausführung vorausgesetzt, dass ein Zielcontainer später die vertrauenswürdige Referenz auflöst.

Quellcode: Verwundbar vs. Sicher

Beispielhafte Python-Schnittstellen, kein JFrog-Code. Im verwundbaren Muster leiten getrennte Parser Cache-Schlüssel und Upstream-Quelle aus derselben unverarbeiteten Anfrage ab. Das gehärtete Muster löst ein einziges unveränderliches, serverseitig autorisiertes RemoteImage auf und verwendet genau diesen Wert sowohl beim Abruf als auch für die Cache-Identität. Erzeugen Sie dieses Objekt aus validierter Konfiguration, nehmen Sie den Remote-Namespace in den Schlüssel auf und binden Sie den Inhalt an einen vertrauenswürdigen unveränderlichen Digest, sofern das System einen bereitstellt. Das zeigt die im Bericht beschriebene defensive Invariante, keinen vollständigen Parser, Produkt-Patch oder Nachbau. Aktualisieren Sie auf eine von JFrog behobene Version.

VERWUNDBARE IMPLEMENTIERUNG
from typing import Callable

Fetch = Callable[[str], bytes]
Select = Callable[[str], str]

def cache_request(
    request: str,
    fetch: Fetch,
    select_local_key: Select,
    select_upstream: Select,
    cache: dict[str, bytes],
) -> None:
    local_key = select_local_key(request)
    upstream = select_upstream(request)
    cache[local_key] = fetch(upstream)
GEHÄRTETER SICHERHEITS-PATCH
from dataclasses import dataclass
from typing import Protocol

@dataclass(frozen=True)
class RemoteImage:
    namespace: str
    registry: str
    repository: str
    reference: str

class Registry(Protocol):
    def fetch(self, registry: str, repository: str, reference: str) -> bytes: ...

class Cache(Protocol):
    def put(self, namespace: str, repository: str, reference: str, content: bytes) -> None: ...

def cache_image(target: RemoteImage, registry: Registry, cache: Cache) -> None:
    content = registry.fetch(target.registry, target.repository, target.reference)
    cache.put(target.namespace, target.repository, target.reference, content)

Checkliste für Engineering & Systemsicherheit

Quellen