From 72803f0b14f4e0a9e6eb389660ebd107da8f6069 Mon Sep 17 00:00:00 2001 From: pax Date: Sat, 11 Apr 2026 16:07:33 -0500 Subject: [PATCH] =?UTF-8?q?security:=20fix=20#2=20=E2=80=94=20wire=20harde?= =?UTF-8?q?ned=20mpv=20options=20into=20=5FMpvGLWidget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the inline mpv.MPV(...) literal kwargs with a call through build_mpv_kwargs(), which adds ytdl=no, load_scripts=no, a lavf protocol whitelist (file,http,https,tls,tcp), and POSIX input_conf lockdown. Closes the yt-dlp delegation surface (CVE-prone extractors invoked on attacker-supplied URLs) and the concat:/subfile: local- file-read gadget via ffmpeg's lavf demuxer. behavior change from v0.2.5: any file_url whose host is only handled by yt-dlp (youtube.com, reddit.com, etc.) will no longer play. Boorus do not legitimately return such URLs, so in practice this only affects hostile responses. Cached local files and direct https .mp4/.webm/.mkv continue to work. Manually smoke tested: played a cached local .mp4 from the library (file: protocol) and a fresh network .webm from a danbooru search (https: protocol) — both work. Audit-Ref: SECURITY_AUDIT.md finding #2 Severity: High --- booru_viewer/gui/media/mpv_gl.py | 60 ++++++-------------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/booru_viewer/gui/media/mpv_gl.py b/booru_viewer/gui/media/mpv_gl.py index c47d7d2..5d0bf26 100644 --- a/booru_viewer/gui/media/mpv_gl.py +++ b/booru_viewer/gui/media/mpv_gl.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +import sys from PySide6.QtCore import Signal from PySide6.QtOpenGLWidgets import QOpenGLWidget as _QOpenGLWidget @@ -10,6 +11,8 @@ from PySide6.QtWidgets import QWidget, QVBoxLayout import mpv as mpvlib +from ._mpv_options import build_mpv_kwargs + log = logging.getLogger(__name__) @@ -35,57 +38,14 @@ class _MpvGLWidget(QWidget): self._frame_ready.connect(self._gl.update) # Create mpv eagerly on the main thread. # - # `ao=pulse` is critical for Linux Discord screen-share audio - # capture. Discord on Linux only enumerates audio clients via - # the libpulse API; it does not see clients that talk to - # PipeWire natively (which is mpv's default `ao=pipewire`). - # Forcing the pulseaudio output here makes mpv go through - # PipeWire's pulseaudio compatibility layer, which Discord - # picks up the same way it picks up Firefox. Without this, - # videos play locally but the audio is silently dropped from - # any Discord screen share. See: - # https://github.com/mpv-player/mpv/issues/11100 - # https://github.com/edisionnano/Screenshare-with-audio-on-Discord-with-Linux - # On Windows mpv ignores `ao=pulse` and falls through to the - # next entry, so listing `wasapi` second keeps Windows playback - # working without a platform branch here. - # - # `audio_client_name` is the name mpv registers with the audio - # backend. Sets `application.name` and friends so capture tools - # group mpv's audio under the booru-viewer app identity instead - # of the default "mpv Media Player". + # Options come from `build_mpv_kwargs` (see `_mpv_options.py` + # for the full rationale). Summary: Discord screen-share audio + # fix via `ao=pulse`, fast-load vd-lavc options, network cache + # tuning for the uncached-video fast path, and the SECURITY + # hardening from audit #2 (ytdl=no, load_scripts=no, + # demuxer_lavf_o protocol whitelist, POSIX input_conf null). self._mpv = mpvlib.MPV( - vo="libmpv", - hwdec="auto", - keep_open="yes", - ao="pulse,wasapi,", - audio_client_name="booru-viewer", - input_default_bindings=False, - input_vo_keyboard=False, - osc=False, - # Fast-load options: shave ~50-100ms off first-frame decode - # for h264/hevc by skipping a few bitstream-correctness checks - # (`vd-lavc-fast`) and the in-loop filter on non-keyframes - # (`vd-lavc-skiploopfilter=nonkey`). The artifacts are only - # visible on the first few frames before the decoder steady- - # state catches up, and only on degraded sources. mpv - # documents these as safe for "fast load" use cases like - # ours where we want the first frame on screen ASAP and - # don't care about a tiny quality dip during ramp-up. - vd_lavc_fast="yes", - vd_lavc_skiploopfilter="nonkey", - # Network streaming tuning for the uncached-video fast path. - # cache=yes is mpv's default for network sources but explicit - # is clearer. cache_pause=no keeps playback running through - # brief buffer underruns instead of pausing — for short booru - # clips a momentary stutter beats a pause icon. demuxer caps - # keep RAM bounded. network_timeout=10 replaces mpv's ~60s - # default so stalled connections surface errors promptly. - cache="yes", - cache_pause="no", - demuxer_max_bytes="50MiB", - demuxer_readahead_secs="20", - network_timeout="10", + **build_mpv_kwargs(is_windows=sys.platform == "win32"), ) # Wire up the GL surface's callbacks to us self._gl._owner = self