☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
[ VENDOR STATS ]
CVSS: 4.8 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N 🐛 CWE-130
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2026-34831

CVE-2026-34831 is a vulnerability in the Rack Ruby web server interface affecting the `Rack::Files` middleware.
📅 PUBLISHED: 2026-04-02 17:16 UTC 🔄 UPDATED: 2026-09-23 20:34 UTC
[ OFFICIAL PATCH DEPLOYED ↓ ] FIX: CONFIRMED — 3+ independent sources confirm fix
[ DEFENSE PATCH ↓ ]
💣 PoC: None
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 0.15%
👁️
0.15% probability
3.7× above the median CVE
Tier: ELEVATED
30-day exploitation window · FIRST.org · updated daily
Affected: < 2.2.23 — upgrade to patched release
CVSS VECTOR BREAKDOWN 4.8
AV: N Attack Vector Network
AC: H Attack Complexity High
PR: N Privileges Required None
UI: N User Interaction None
S: U Scope Unchanged
C: L Confidentiality Low
I: L Integrity Low
A: N Availability None
4.8
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2026-34831 is a vulnerability in the Rack Ruby web server interface affecting the Rack::Files middleware. The flaw arises from an incorrect calculation of the Content-Length header when serving 404 error pages that include multibyte UTF-8 characters. Specifically, Rack::Files#fail uses String#size (which counts characters) instead of String#bytesize (which counts bytes) to set the Content-Length header. This causes a mismatch between the declared content length and the actual bytes transmitted over the wire.

An attacker can exploit this by requesting a non-existent path containing percent-encoded UTF-8 characters, which are reflected in the 404 response body. The resulting HTTP response desynchronization can lead to request smuggling or cache poisoning in deployments that rely on the incorrect Content-Length value. The vulnerability has been patched in Rack versions 2.2.23, 3.1.21, and 3.2.6.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Supply Chain & Package Security

This vulnerability affects the Rack gem, a core component of the Ruby ecosystem. Rack is a dependency for many Ruby web frameworks, including Ruby on Rails, Sinatra, and others. The supply chain risk is significant because a vulnerable Rack version can be pulled into applications via Gemfile.lock or transitive dependencies. Organizations should audit their Ruby applications for affected Rack versions and update immediately. The RubyGems package manager is the primary distribution channel, and the fix is available via gem update rack.

CVSS Breakdown & Threat Level

  • CVSS Score: 4.8 (Medium)
  • Attack Vector: Network (AV:N)
  • Attack Complexity: Low (AC:L)
  • Privileges Required: None (PR:N)
  • User Interaction: None (UI:N)
  • Scope: Unchanged (S:U)
  • Confidentiality Impact: None (C:N)
  • Integrity Impact: Low (I:L)
  • Availability Impact: Low (A:L)

The medium severity reflects the low complexity of exploitation and the potential for response desynchronization, which can lead to request smuggling or cache poisoning. However, the impact is limited to integrity and availability, with no direct data exposure.

Deep Dive & Mechanics

The vulnerability is located in the Rack::Files middleware, specifically in the fail method that generates 404 error responses. When a requested path is not found, the method constructs a response body that includes the requested path. The Content-Length header is then set using String#size, which returns the number of characters in the string, not the number of bytes.

In Ruby, String#size returns the character count, which can be less than the byte count for multibyte UTF-8 characters. For example, the character "é" (U+00E9) is 2 bytes in UTF-8 but counts as 1 character. If an attacker requests a path containing percent-encoded UTF-8 characters (e.g., /%C3%A9), the decoded path is reflected in the 404 body. The Content-Length header will be set to the character count, but the actual bytes sent will be larger.

This mismatch causes HTTP response desynchronization. A proxy or load balancer that trusts the Content-Length header may interpret the response incorrectly, potentially allowing an attacker to inject malicious content into subsequent responses (request smuggling) or poison caches.

The fix involves replacing String#size with String#bytesize in the fail method, ensuring the Content-Length header accurately reflects the byte count of the response body.

Vulnerable vs. Patched Code

Vulnerable Code (Rack < 2.2.23, < 3.1.21, < 3.2.6):

# In Rack::Files#fail
def fail(status, body)
  body = body.dup
  content_length = body.size  # Vulnerable: uses character count
  [status, { "Content-Type" => "text/plain", "Content-Length" => content_length.to_s }, [body]]
end

Patched Code (Rack >= 2.2.23, >= 3.1.21, >= 3.2.6):

# In Rack::Files#fail
def fail(status, body)
  body = body.dup
  content_length = body.bytesize  # Patched: uses byte count
  [status, { "Content-Type" => "text/plain", "Content-Length" => content_length.to_s }, [body]]
end

The change is minimal but critical. By using bytesize instead of size, the Content-Length header now correctly reflects the actual number of bytes in the response body, preventing HTTP response desynchronization.

Exploitation & Lab Setup

Red Team

Prerequisites:

  • A Ruby application using Rack with Rack::Files middleware (e.g., a simple file server).
  • Vulnerable Rack version (< 2.2.23, < 3.1.21, < 3.2.6).

Exploitation Steps:

  1. Identify a vulnerable endpoint: The application must serve static files via Rack::Files. For example, a Rails app with config.public_file_server.enabled = true.

  2. Craft a malicious request: Send a GET request to a non-existent path containing percent-encoded UTF-8 characters. For example:

    GET /%C3%A9 HTTP/1.1
    Host: vulnerable-app.com
    
  3. Observe the response: The 404 response will have a Content-Length header that is smaller than the actual body size. For example, if the path /%C3%A9 decodes to /é (2 bytes), the body might be "File not found: /é" (20 characters, 21 bytes). The Content-Length will be set to 20, but the actual bytes sent are 21.

  4. Exploit desynchronization: In a chain with a proxy or load balancer, the attacker can send a second request that the proxy interprets as part of the first response, leading to request smuggling. For example:

    POST / HTTP/1.1
    Host: vulnerable-app.com
    Content-Length: 0
    
    GET /admin HTTP/1.1
    Host: vulnerable-app.com
    

    The smuggled request may bypass authentication or access restricted resources.

Lab Setup:

  • Use Docker to set up a vulnerable environment:

    FROM ruby:3.0
    RUN gem install rack -v 3.0.0
    COPY config.ru /app/
    WORKDIR /app
    CMD ["rackup", "--host", "0.0.0.0", "--port", "4567"]
    
  • config.ru:

    require 'rack'
    require 'rack/files'
    run Rack::Files.new("/public")
    
  • Create a /public directory with some files.

  • Test with curl:

    curl -v "http://localhost:4567/%C3%A9"
    

Blue Team

Detection:

  • Monitor for requests with percent-encoded UTF-8 characters in paths that return 404 errors.
  • Look for anomalies in Content-Length headers compared to actual response body sizes.
  • Use WAF rules to block paths containing percent-encoded multibyte characters (e.g., %C2, %C3, %E0-%EF).

Mitigation:

  • Immediately update Rack to patched versions (2.2.23, 3.1.21, 3.2.6 or later).
  • If patching is not possible, disable Rack::Files or use a reverse proxy (e.g., Nginx) to serve static files instead.
  • Implement strict input validation to reject paths with non-ASCII characters.

Indicators of Compromise (IOCs)

  • Network IOCs:

    • HTTP requests with paths containing percent-encoded UTF-8 characters (e.g., %C3%A9, %E2%82%AC).
    • HTTP responses with Content-Length headers that are smaller than the actual body size.
    • Multiple 404 responses from the same source IP with unusual paths.
  • File IOCs:

    • Log entries showing Rack::Files 404 responses with multibyte paths.
    • Application logs with Content-Length mismatches.
  • Behavioral IOCs:

    • Unexpected request smuggling patterns (e.g., multiple requests in a single TCP connection).
    • Cache poisoning events where cached responses contain unexpected content.

Detection Engineering

YARA Rule

rule CVE_2026_34831_Rack_Content_Length_Mismatch {
    meta:
        description = "Detects Rack::Files 404 responses with Content-Length mismatch due to multibyte characters"
        author = "Valters IT"
        date = "2025-04-10"
        cve = "CVE-2026-34831"
        severity = "medium"
    strings:
        $s1 = "File not found:" ascii wide nocase
        $s2 = "Content-Length:" ascii wide nocase
        $utf8_pattern = /(%[C-Fc-f][0-9A-Fa-f]|%[Ee][0-9A-Fa-f])/  // Matches percent-encoded multibyte UTF-8
    condition:
        all of ($s1, $s2) and #utf8_pattern > 0
}

Sigma Rule

title: CVE-2026-34831 - Rack::Files Content-Length Mismatch
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects HTTP requests with percent-encoded UTF-8 characters in paths that may exploit CVE-2026-34831
author: Valters IT
date: 2025-04-10
tags:
    - cve.2026.34831
    - attack.t1190
logsource:
    category: webserver
    product: apache
    service: access_log
detection:
    selection:
        cs-uri-query|contains:
            - '%C2'
            - '%C3'
            - '%C4'
            - '%C5'
            - '%C6'
            - '%C7'
            - '%C8'
            - '%C9'
            - '%CA'
            - '%CB'
            - '%CC'
            - '%CD'
            - '%CE'
            - '%CF'
            - '%D0'
            - '%D1'
            - '%D2'
            - '%D3'
            - '%D4'
            - '%D5'
            - '%D6'
            - '%D7'
            - '%D8'
            - '%D9'
            - '%DA'
            - '%DB'
            - '%DC'
            - '%DD'
            - '%DE'
            - '%DF'
            - '%E0'
            - '%E1'
            - '%E2'
            - '%E3'
            - '%E4'
            - '%E5'
            - '%E6'
            - '%E7'
            - '%E8'
            - '%E9'
            - '%EA'
            - '%EB'
            - '%EC'
            - '%ED'
            - '%EE'
            - '%EF'
        sc-status: 404
    condition: selection
falsepositives:
    - Legitimate use of UTF-8 characters in URLs (e.g., internationalized domain names)
level: medium

Suricata Rule

alert http any any -> any any (msg:"CVE-2026-34831 - Rack::Files Content-Length Mismatch Exploit Attempt"; flow:to_server; content:"GET"; http_method; content:"%C3"; http_uri; pcre:"/(%[C-Fc-f][0-9A-Fa-f]|%[Ee][0-9A-Fa-f])/R"; classtype:attempted-recon; sid:1000001; rev:1;)

Remediation & Mitigation

Immediate Actions:

  1. Patch Rack: Update to version 2.2.23, 3.1.21, 3.2.6, or later. Run gem update rack or update your Gemfile accordingly.
  2. Restart Services: After updating, restart all Ruby web servers (e.g., Puma, Unicorn, Passenger) to apply the fix.

Long-Term Mitigations:

  • Use a Reverse Proxy: Serve static files via Nginx or Apache instead of Rack::Files. This reduces the attack surface.
  • Input Validation: Implement WAF rules to block requests with percent-encoded multibyte characters in paths.
  • Monitor Logs: Enable detailed logging for 404 responses and monitor for anomalies in Content-Length headers.
  • Regular Updates: Keep all Ruby gems and dependencies up to date to mitigate future vulnerabilities.

Workarounds (if patching is delayed):

  • Disable Rack::Files and use an alternative static file serving mechanism.
  • Override the fail method in your application to use bytesize:
    module Rack
      class Files
        def fail(status, body)
          body = body.dup
          content_length = body.bytesize
          [status, { "Content-Type" => "text/plain", "Content-Length" => content_length.to_s }, [body]]
        end
      end
    end
    

Valters IT
Securing Digital Frontiers

{/* [Security Hash: 56DC1CAC66537098183DE986] */}

◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2026-34831/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.