CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-126188

CVE-2026-126188: Local Media Information Disclosure in Ruby on Rails Active Storage via FFmpeg Demuxer Selection

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 12, 2026·10 min read·1 visit

Executive Summary (TL;DR)

Active Storage prior to Rails 8.0.5.2 and 8.1.4.1 passes uploaded media files to ffmpeg and ffprobe without the -format_whitelist argument. Attackers can upload an HLS (.m3u8) playlist masquerading as a video or audio file to read local media files via the file:// protocol and leak their contents through generated thumbnail previews or metadata records.

CVE-2026-126188 (GHSA-3f4q-8x5m-76v8) is an information disclosure vulnerability in the Active Storage component of Ruby on Rails prior to versions 8.0.5.2 and 8.1.4.1. When generating previews or extracting metadata from uploaded media files, Active Storage invokes the external command-line tools ffmpeg and ffprobe without specifying a format whitelist. An attacker who can upload a crafted HTTP Live Streaming (HLS) playlist while declaring a standard video or audio MIME type can cause FFmpeg to engage the HLS demuxer, resolve file:// segment URIs, and disclose visual frames or metadata from local media files readable by the Rails application process.

Vulnerability Overview

Active Storage is the built-in framework in Ruby on Rails for facilitating file uploads to cloud storage services or local disks and attaching those files to Active Record objects. Beyond raw storage, Active Storage provides automated post-processing capabilities for media files. Specifically, ActiveStorage::Previewer::VideoPreviewer generates thumbnail images from video attachments, while ActiveStorage::Analyzer::VideoAnalyzer and ActiveStorage::Analyzer::AudioAnalyzer inspect uploaded media blobs to extract technical metadata such as duration, dimensions, bitrates, and stream attributes.

To perform these operations, Active Storage shells out to the ffmpeg and ffprobe binaries installed on the host operating system. Prior to Ruby on Rails versions 8.0.5.2 and 8.1.4.1, these external commands were executed directly on the downloaded temporary blob file without constraining which container formats or demuxers FFmpeg was allowed to initialize. Consequently, FFmpeg relied on its default content-probing behavior to inspect the binary signature of the uploaded file rather than enforcing that the file matched a safe container format.

This behavior creates an exposure of sensitive information (CWE-200) when an application accepts untrusted media uploads—particularly via Active Storage's direct upload mechanism, where the client supplies the declared content_type. An attacker can upload a text-based HTTP Live Streaming (HLS) playlist file (#EXTM3U) while declaring its MIME type as video/mp4 or audio/mpeg. When Active Storage passes this blob to ffmpeg or ffprobe, FFmpeg's format probing selects the hls demuxer.

Once engaged, the hls demuxer parses segment URIs listed inside the playlist, which supports the file:// URI scheme. If the attacker knows or can predict the filesystem path of a local media file readable by the Rails application process, FFmpeg opens that local file as a media segment. Depending on which Active Storage operation is triggered, the server either renders a visual frame from the local file into an attacker-accessible preview image or extracts the local file's audio/video stream metadata into the attachment's database record.

Root Cause Analysis

The root cause of CVE-2026-126188 is the absence of explicit demuxer restrictions at the boundary where Active Storage constructs command-line arguments for ffmpeg and ffprobe. By design, FFmpeg supports hundreds of container formats, playlist structures, and network/filesystem protocol handlers. When invoked with -i <input_file> (in ffmpeg) or <input_file> (in ffprobe) without the -format_whitelist flag, libavformat reads the leading bytes of the input file and scores registered demuxers based on magic bytes and structural markers.

In Active Storage, determining whether a blob is eligible for video previewing or media analysis depends on the blob's content_type attribute. For instance, ActiveStorage::Previewer::VideoPreviewer.accept? checks if the blob's content type matches a video MIME type supported by the application. When using Active Storage direct uploads (/rails/active_storage/direct_uploads), the client sends a JSON payload specifying the filename, byte_size, checksum, and content_type before uploading the raw file bytes directly to the storage service. If server-side MIME type sniffing is bypassed or disabled (such as setting identify: false or relying on client-provided metadata during direct upload), the blob retains the attacker-controlled content_type.

When the application subsequently requests a preview variant or executes the background analysis job (ActiveStorage::AnalyzeJob), Active Storage downloads the blob to a local temporary file and invokes ffmpeg or ffprobe. Even though the blob is marked as video/mp4 in the database, libavformat inspects the file's actual contents, detects the #EXTM3U header, and initializes the hls demuxer.

Within FFmpeg, the hls demuxer acts as a meta-container that sequentially opens underlying media segments specified in the playlist body. By default, FFmpeg permits the hls demuxer to use the file protocol handler. When the playlist contains an entry such as file:///var/data/internal_recording.mp4, FFmpeg opens that path on the server's local filesystem, decodes its stream headers or video frames, and returns the output to Active Storage.

Code Analysis

Prior to the security patch, three distinct classes in the activestorage gem invoked FFmpeg utilities without format restrictions: ActiveStorage::Previewer::VideoPreviewer, ActiveStorage::Analyzer::VideoAnalyzer, and ActiveStorage::Analyzer::AudioAnalyzer. In VideoPreviewer, the draw_relevant_frame_from method constructed the ffmpeg command by interpolating ActiveStorage.video_preview_arguments directly after -i file.path. Similarly, both analyzer classes executed ffprobe with JSON output flags and passed file.path directly as the final positional argument.

To remediate the vulnerability in commits 3b1f2627538dc597cd973530c08514a26c2b0282 (Rails 8.1) and 69aff80d115bbb9d1e82fd6c6f2fd3ddeafb958b (Rails 8.0), the Rails maintainers introduced a module-level configuration attribute ffmpeg_allowed_formats in activestorage/lib/active_storage.rb alongside a helper method ffmpeg_format_whitelist_arguments:

# activestorage/lib/active_storage.rb
mattr_accessor :video_preview_arguments, default: "-y -vframes 1 -f image2"
 
# Define a strict default allowlist of standard container and audio formats,
# explicitly excluding playlist/reference demuxers like 'hls' or 'concat'.
mattr_accessor :ffmpeg_allowed_formats, default: %w[ mov matroska avi mpeg mpegts flv asf ogg mp3 wav flac aac aiff caf ].freeze
 
def self.ffmpeg_format_whitelist_arguments # :nodoc:
  # Construct the -format_whitelist CLI flag for ffmpeg/ffprobe unless explicitly set to nil
  [ "-format_whitelist", Array(ffmpeg_allowed_formats).join(",") ] unless ffmpeg_allowed_formats.nil?
end

In ActiveStorage::Previewer::VideoPreviewer, the patch splats *ActiveStorage.ffmpeg_format_whitelist_arguments immediately before the -i input flag. In FFmpeg's command-line parser, options affecting input demuxing must precede the -i argument to bind to the input context:

# activestorage/lib/active_storage/previewer/video_previewer.rb
def draw_relevant_frame_from(file, &block)
  # BEFORE:
  # draw self.class.ffmpeg_path, "-i", file.path, *Shellwords.split(ActiveStorage.video_preview_arguments), "-", &block
 
  # AFTER: Enforce -format_whitelist prior to reading input file
  draw self.class.ffmpeg_path, *ActiveStorage.ffmpeg_format_whitelist_arguments, "-i", file.path, *Shellwords.split(ActiveStorage.video_preview_arguments), "-", &block
end

The exact same argument array is injected into ActiveStorage::Analyzer::VideoAnalyzer and ActiveStorage::Analyzer::AudioAnalyzer within their respective probe_from methods. Additionally, the patch adds a warning log when ffprobe exits with a non-zero status so administrators can identify when legitimate uploads are rejected due to format restrictions:

# activestorage/lib/active_storage/analyzer/video_analyzer.rb
IO.popen([
  self.class.ffprobe_path,
  "-print_format", "json",
  "-show_streams",
  "-show_format",
  "-v", "error",
  *ActiveStorage.ffmpeg_format_whitelist_arguments, # Restrict allowed demuxers
  file.path
]) do |output|
  JSON.parse(output.read)
end.tap do
  logger.warn "Video analysis failed because ffprobe exited with status #{$?.exitstatus}. The file may be corrupt, or in a format outside config.active_storage.ffmpeg_allowed_formats." unless $?.success?
end

> [!NOTE] > Assessment of Fix Completeness: Enforcing -format_whitelist at the libavformat layer is effective at preventing FFmpeg from initializing playlist and reference-based demuxers such as hls, concat, dash, or sdp. Because libavformat validates the probed format against the comma-separated whitelist before invoking the demuxer's read_header callback, playlist segment resolution is blocked entirely. However, if an application administrator overrides config.active_storage.ffmpeg_allowed_formats to nil or manually adds hls or concat to the array, the protection is bypassed.

Exploitation

Exploiting CVE-2026-126188 requires an application endpoint that accepts file uploads via Active Storage and subsequently performs either video preview generation or media analysis on the attachment. The attacker does not need authentication if the upload endpoint is publicly accessible, though in many applications upload functionality is restricted to authenticated users. Crucially, the attacker must also know or predict the exact filesystem path of a local media file on the server that the Rails user account has read permissions to access.

To begin the attack, the adversary constructs a minimal HLS M3U8 playlist referencing the target local file via the file:// URI scheme. The target file must be in a media or image format that FFmpeg is capable of decoding into video frames or audio/video streams (for example, .mp4, .mov, .mkv, .mp3, or image files that FFmpeg can treat as single-frame video streams):

#EXTM3U
#EXT-X-TARGETDURATION:10
#EXTINF:10,
file:///var/app/current/storage/internal/confidential_meeting.mp4
#EXT-X-ENDLIST

Next, the attacker initiates an upload request, declaring the content_type as video/mp4 so that Active Storage routes the blob to VideoPreviewer and VideoAnalyzer:

POST /rails/active_storage/direct_uploads HTTP/1.1
Host: vulnerable-rails-app.example.com
Content-Type: application/json
 
{
  "blob": {
    "filename": "presentation.mp4",
    "content_type": "video/mp4",
    "byte_size": 109,
    "checksum": "1B2M2Y8AsgTpgAmY7PhCfg=="
  }
}

After uploading the M3U8 payload to the signed URL returned by the direct upload endpoint and attaching the signed blob ID to a model record, the application either queues ActiveStorage::AnalyzeJob or renders a preview URL in a view template (e.g., url_for(record.attachment.preview(resize_to_limit: [640, 480]))). When the preview URL is requested, VideoPreviewer executes ffmpeg -i /tmp/ActiveStorage-... -y -vframes 1 -f image2 -. FFmpeg parses the M3U8 playlist, reads the first frame from /var/app/current/storage/internal/confidential_meeting.mp4, encodes it as a JPEG or PNG image, and serves it back to the attacker.

The official Rails security patch includes unit tests in activestorage/test/previewer/video_previewer_test.rb and activestorage/test/analyzer/video_analyzer_test.rb that demonstrate this exact reproduction mechanism:

def create_playlist_blob(referencing:, filename:, content_type:)
  playlist = <<~M3U8
    #EXTM3U
    #EXT-X-TARGETDURATION:10
    #EXTINF:10,
    file://#{file_fixture(referencing).realpath}
    #EXT-X-ENDLIST
  M3U8
 
  create_blob(data: playlist, filename: filename, content_type: content_type, identify: false)
end

Impact Assessment

The security impact of CVE-2026-126188 is limited to unauthorized local information disclosure, reflected in its CVSS v3.1 base score of 3.7 (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N). The vulnerability does not permit arbitrary file read of non-media files such as /etc/passwd, database configuration files (config/database.yml), or Ruby source code, because VideoPreviewer only outputs decoded visual frames and VideoAnalyzer/AudioAnalyzer only extract structured stream metadata (duration, dimensions, codec tags) parsed by ffprobe.

However, the confidentiality impact (C:L) is tangible in multi-tenant applications or deployments that store sensitive attachments locally on disk (using the Disk storage service in config/storage.yml). Although Active Storage generates random keys for blobs stored on disk, an attacker who discovers internal filesystem paths through a separate path disclosure bug—or who targets predictable temporary files in /tmp or shared mounted volumes—can extract visual frames from other users' private videos or documents.

Furthermore, if the attacker controls the FFmpeg preview arguments or chains multiple media segments in the M3U8 playlist, they can probe for the existence of local media files on the server. When a referenced file:// path exists and contains valid media, VideoAnalyzer populates blob.metadata with width, height, and duration. When the file does not exist, ffprobe fails and leaves those metadata keys empty, providing a side-channel oracle for verifying local media file paths.

According to FIRST EPSS metrics, the vulnerability carries a low exploitation probability of 0.28% (20.62nd percentile), and it is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. The high attack complexity (AC:H) stems from the requirement to know exact local media paths and the constraint that only files decodable by FFmpeg can have their contents or metadata leaked.

Remediation

To remediate CVE-2026-126188, upgrade Ruby on Rails (rails and activestorage gems) to version 8.0.5.2 (for the 8.0 release branch) or 8.1.4.1 (for the 8.1 release branch) or later. These releases enforce -format_whitelist across all ffmpeg and ffprobe invocations by default, restricting FFmpeg to the following container formats: mov, matroska, avi, mpeg, mpegts, flv, asf, ogg, mp3, wav, flac, aac, aiff, and caf.

After upgrading, audit the application's media processing requirements. If the application legitimately processes less common container formats that are excluded from the default allowlist—such as Material Exchange Format (mxf), Digital Video (dv), or WavPack (wv)—append only the required demuxer identifiers in config/application.rb:

# config/application.rb
config.active_storage.ffmpeg_allowed_formats += %w[ mxf dv ]

> [!WARNING] > Never add playlist or reference demuxers (such as hls, concat, or dash) to config.active_storage.ffmpeg_allowed_formats, and never set config.active_storage.ffmpeg_allowed_formats = nil in environments that process untrusted uploads. Doing so disables the format whitelist and reintroduces the vulnerability.

For applications that cannot immediately upgrade to Rails 8.0.5.2 or 8.1.4.1, apply an initializer patch (config/initializers/active_storage_ffmpeg_whitelist.rb) that prepends -format_whitelist to ActiveStorage.video_preview_arguments and overrides probe_from in ActiveStorage::Analyzer::VideoAnalyzer and ActiveStorage::Analyzer::AudioAnalyzer:

# config/initializers/active_storage_ffmpeg_whitelist.rb
Rails.application.config.after_initialize do
  allowed_formats = "mov,matroska,avi,mpeg,mpegts,flv,asf,ogg,mp3,wav,flac,aac,aiff,caf"
 
  ActiveStorage::Previewer::VideoPreviewer.prepend(Module.new do
    private
      def draw_relevant_frame_from(file, &block)
        draw self.class.ffmpeg_path, "-format_whitelist", allowed_formats, "-i", file.path, *Shellwords.split(ActiveStorage.video_preview_arguments), "-", &block
      end
  end)
end

Official Patches

Ruby on RailsGitHub Security Advisory GHSA-3f4q-8x5m-76v8
Ruby on RailsRuby on Rails v8.0.5.2 Release Notes
Ruby on RailsRuby on Rails v8.1.4.1 Release Notes

Fix Analysis (2)

Technical Appendix

CVSS Score
3.7/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
EPSS Probability
0.28%
Top 79% most exploited

Affected Systems

Ruby on Rails (activestorage gem) < 8.0.5.2Ruby on Rails (activestorage gem) >= 8.1.0, < 8.1.4.1

Affected Versions Detail

Product
Affected Versions
Fixed Version
activestorage (Ruby on Rails)
Rails
< 8.0.5.28.0.5.2
activestorage (Ruby on Rails)
Rails
>= 8.1.0, < 8.1.4.18.1.4.1
AttributeDetail
Vulnerability IDCVE-2026-126188 / GHSA-3f4q-8x5m-76v8
Weakness ClassCWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Affected ComponentActive Storage (VideoPreviewer, VideoAnalyzer, AudioAnalyzer)
Attack VectorNetwork (Crafted HLS .m3u8 Direct Upload with file:// Segment URIs)
CVSS v3.1 Score3.7 Low (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N)
EPSS Score0.28% (20.62nd Percentile)
ImpactUnauthorized disclosure of local media frames and metadata readable by the Rails process
Patched VersionsRails 8.0.5.2, Rails 8.1.4.1

MITRE ATT&CK Mapping

T1005Data from Local System
Collection
T1552Unsecured Credentials
Credential Access
CWE-200
Exposure of Sensitive Information to an Unauthorized Actor

The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.

Vulnerability Timeline

Security patches authored and committed to Rails repository branches by Mike Dalessio.
2026-10-31
Rails release preparations completed for versions 8.0.5.2 and 8.1.4.1.
2026-11-04
GitHub Security Advisory GHSA-3f4q-8x5m-76v8 and CVE-2026-126188 published.
2026-11-10
CVE-2026-126188 published in the National Vulnerability Database (NVD).
2026-11-11
NVD and CVE records updated with finalized CVSS v3.1 scoring and CWE-200 classification.
2026-11-12

References & Sources

  • [1]GitHub Security Advisory GHSA-3f4q-8x5m-76v8
  • [2]NVD Vulnerability Detail: CVE-2026-126188
  • [3]CVE.org Record: CVE-2026-126188
  • [4]Ruby on Rails Release v8.0.5.2
  • [5]Ruby on Rails Release v8.1.4.1
  • [6]Official Patch Commit (Rails 8.1 branch)
  • [7]Official Patch Commit (Rails 8.0 branch)

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 2 hours ago•CVE-2026-126206
5.3

CVE-2026-126206: Cross-Site Scripting via HTML5 Named Solidus Entity in Loofah URI Validator

CVE-2026-126206 (GHSA-jcff-cj73-4w4f) is a Cross-Site Scripting (XSS) vulnerability in version 2.25.2 of the Loofah Ruby gem. The vulnerability stems from an incomplete character reference normalization routine in the `Loofah::HTML5::Scrub.allowed_uri?` method, which fails to decode the HTML5 named character reference `&sol;` (representing the solidus character `/`). Consequently, a crafted `data:` URI such as `data:text&sol;html,<script>alert(1)</script>` bypasses mediatype validation by triggering the WHATWG MIME parser fallback to `text/plain`, while web browsers later resolve `&sol;` to `/` and execute the payload as `text/html`.

Alon Barad
Alon Barad
3 views•9 min read
•about 3 hours ago•CVE-2026-125325
5.9

CVE-2026-125325: Cross-Request Information Disclosure via Shared BM25 Index Race Condition in pgEdge RAG Server

pgEdge RAG Server versions prior to 2.0.0 contain a race condition in the hybrid search pipeline orchestrator (CWE-362, CWE-488). The server maintains a single shared, in-memory BM25 index instance across all incoming HTTP requests on a pipeline. Concurrent queries to the unauthenticated HTTP REST API interleave non-atomic clear, document addition, and search operations on this singleton index. As a result, documents fetched using one caller's search filter can be queried and returned to another concurrent caller, bypassing multi-tenant data isolation without generating any anomalous audit trail in server or database logs.

Amit Schendel
Amit Schendel
2 views•10 min read
•about 5 hours ago•CVE-2026-118740
9.1

CVE-2026-118740: Missing Authorization in Microsoft Aspire Dashboard Blazor Router

CVE-2026-118740 is a Missing Authorization (CWE-862) vulnerability in the Microsoft Aspire Dashboard and Aspire.Dashboard.Sdk.linux-x64 packages. In versions 13.6.1 prior to 13.6.5, an architectural flaw in the Blazor routing configuration (Routes.razor) causes unmapped (404 / Not-Found) routes to bypass the AuthorizeRouteView component. By navigating to an arbitrary non-existent route, an unauthenticated remote attacker forces the application into the NotFound template, which unconditionally renders the primary MainLayout component and initializes global user interface services, interaction providers, and underlying SignalR/Blazor circuits without verifying authentication credentials.

Alon Barad
Alon Barad
5 views•9 min read
•1 day ago•CVE-2026-120006
7.5

CVE-2026-120006: Elevation of Privilege in .NET Aspire via Unintended Dashboard Endpoint Tunneling

An elevation of privilege vulnerability exists in .NET Aspire versions prior to 13.6.5 due to the insertion of sensitive information into sent data (CWE-201). When the Developer Control Plane (DCP) container tunneling feature is enabled, the orchestration engine implicitly exposes all endpoints of the Aspire Dashboard—including its administrative frontend and management APIs—to containerized workloads instead of restricting tunnel access solely to OpenTelemetry Protocol (OTLP) collection endpoints. This exposure allows an attacker operating within a compromised or untrusted container to query the dashboard frontend, extract sensitive environment variables and connection strings, and elevate privileges across the host orchestration boundary.

Amit Schendel
Amit Schendel
6 views•10 min read
•1 day ago•CVE-2026-118750
7.5

CVE-2026-118750: Uncontrolled Resource Allocation in ASP.NET Core FileBufferingReadStream

CVE-2026-118750 is an uncontrolled resource allocation vulnerability (CWE-770) affecting the Microsoft.AspNetCore.WebUtilities component in ASP.NET Core. Specifically, the FileBufferingReadStream class eagerly allocates large memory buffers from the shared ArrayPool<byte> inside its constructor prior to reading any incoming request payload data. An unauthenticated remote attacker can exploit this behavior by opening numerous concurrent connections and stalling or omitting request body transmission, exhausting shared memory pools and causing a server-wide Denial of Service (DoS).

Amit Schendel
Amit Schendel
6 views•10 min read
•1 day ago•CVE-2026-114155
7.5

CVE-2026-114155: Local Elevation of Privilege via TOCTOU Race Condition in Microsoft .NET dotnet-watch

CVE-2026-114155 is a local elevation of privilege vulnerability affecting Microsoft .NET on Linux and macOS platforms. The vulnerability exists within the dotnet-watch (Hot Reload) component and is caused by a Time-of-Check Time-of-Use (TOCTOU) race condition (CWE-367) during the generation and execution of temporary XML solution files (.slnx) in shared system temporary directories. A local attacker with low privileges can intercept and modify the temporary solution file before MSBuild evaluates it, achieving arbitrary code execution in the security context of the user running dotnet-watch.

Alon Barad
Alon Barad
6 views•9 min read