CVE-2026-25500
Medium · 5.4CVSS
5.4
EPSS
0.3%
Published
Feb 18, 2026
CISA due date
—
Cloudanix analysis
A web page that lists files can turn a specially named file into a clickable link that runs unwanted code in a user’s browser.
- Exploitation
- Requires User Interaction
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- Library
- Class
- XSS
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This is a stored cross-site scripting issue in Rack::Directory directory-index generation. In affected Rack versions before 2.2.22, 3.1.20, and 3.2.5, file names are rendered into clickable HTML links without preventing dangerous URI schemes in the anchor href. If an attacker can create or influence a file name in a directory exposed through Rack::Directory, and that basename begins with a scheme such as javascript:, the generated listing can contain a link that executes script in the victim’s browser when clicked. The flaw requires attacker ability to place or rename a file and user interaction, but successful exploitation can run script in the security context of the affected web application origin, enabling limited confidentiality and integrity impact such as session interaction, credential or token theft where accessible to JavaScript, phishing, or unauthorized actions as the victim.
Why it matters to the business
Applications exposing Rack::Directory listings may present malicious file entries as legitimate links, creating a user-driven path to browser-side compromise. The main operational risk is abuse of trusted application pages to steal user data, perform actions as users, or damage user trust. The vulnerability has a moderate CVSS score of 5.4, low EPSS probability of 0.00224, no known CISA KEV listing, no known ransomware association, and no reported exploit maturity in the supplied data, so remediation should be prioritized for internet-facing applications, administrative portals, file-sharing workflows, development tools, and any environment where untrusted users can create files in listed directories.
How an attack unfolds
An attacker first needs a way to create, upload, synchronize, extract, or rename a file in a directory that is later served by Rack::Directory. The attacker chooses a basename beginning with a JavaScript URI scheme, such as javascript:alert(1), or a more harmful payload. When a victim browses the Rack-generated directory index, Rack renders that file as an HTML anchor whose href points directly to the JavaScript URI. The directory listing itself may appear normal, but clicking the malicious file entry causes the browser to execute the embedded JavaScript under the affected site’s origin. From there, the attacker’s script may read accessible page content, interact with the application as the victim, redirect the victim to phishing content, or attempt to exfiltrate data available to client-side JavaScript. The attack does not require server-side code execution and does not generally leave a follow-up HTTP request for the clicked javascript: link because execution occurs locally in the browser.
How to fix it
Upgrade Rack to a fixed release: 2.2.22 or later on the 2.2 branch, 3.1.20 or later on the 3.1 branch, or 3.2.5 or later on the 3.2 branch. For source-based deployments, ensure the Rack code includes fixed commit 0cc2e00b22dffc33955ef912569f01e515a406e1 or a later equivalent. Regenerate lockfiles and rebuild application images or packages so the runtime dependency is actually updated. If immediate upgrade is not possible, disable Rack::Directory for untrusted paths, avoid exposing directory listings publicly, restrict write access to directories that are listed, reject or rename uploaded/extracted files whose basenames begin with executable URI schemes such as javascript:, data:, vbscript:, or similar, and add a Content Security Policy that reduces the impact of inline/script execution where compatible. Do not rely on user training as the primary control because the malicious entry is rendered by a trusted application page.
How to confirm the fix worked
Confirm the deployed Rack version at runtime and in dependency manifests is 2.2.22, 3.1.20, 3.2.5, or newer as appropriate. Validate that application images, gems, bundled dependencies, and lockfiles no longer resolve to vulnerable Rack versions. In a non-production test environment, create a file with a basename such as javascript:alert(1) in a directory served by Rack::Directory and load the directory index; the fixed behavior should not render a clickable href that preserves the javascript: scheme. Review generated HTML for directory entries and verify dangerous schemes are escaped, neutralized, or not used as navigable link targets. Also verify that directory listing is disabled or access-controlled where it is not required.
Typical attack path
- Identify an application or endpoint that exposes directory listings through Rack::Directory.
- Obtain the ability to create, upload, extract, synchronize, or rename a file in a listed directory.
- Create a file whose basename begins with a dangerous URI scheme, for example javascript:alert(1).
- Wait for or lure a victim to open the affected directory index page.
- Victim clicks the malicious file entry in the generated listing.
- Browser executes attacker-controlled JavaScript in the context of the affected application origin.
- Attacker uses the script to perform victim-context actions, steal accessible client-side data, or redirect the victim.
How to detect it
To determine whether exploitation may have occurred, focus on evidence that a suspicious file name was created in a directory exposed through Rack::Directory and that users subsequently visited the corresponding directory index. Useful sources include web server access logs, Rack/Rails application logs, file upload logs, WebDAV or file-management audit logs, archive extraction logs, CI/CD artifact logs, object storage synchronization logs, endpoint file creation telemetry, and web proxy logs. Search for file basenames beginning with javascript: and URL-encoded or case-varied forms. Because clicking a javascript: link executes in the browser without making a normal HTTP request to that href, absence of a request for the malicious href does not rule out exploitation. Stronger evidence includes suspicious file creation or rename events, rendered directory pages containing href="javascript:, user reports of unexpected popups or redirects after clicking directory entries, browser telemetry showing script execution or suspicious outbound requests immediately after visiting a directory index, and downstream requests consistent with client-side exfiltration. If web content was cached by a proxy or CDN, inspect cached directory index HTML for dangerous href values. If threat hunting finds matching file names, identify who created them, when they appeared, which directory listings exposed them, and which users accessed those listings afterward.
- href="javascript:
- href='javascript:
- javascript:alert(1)
- javascript:
- %6a%61%76%61%73%63%72%69%70%74%3a
- javascript%3A
- Rack::Directory
- basename starts with `javascript:`
What your security team should do
- Inventory applications using Rack::Directory or exposing Rack-generated directory listings, especially internet-facing services and file browsing workflows.
- Upgrade Rack to 2.2.22, 3.1.20, 3.2.5, or later, and verify the fixed version is present in production artifacts.
- Prioritize systems where untrusted or low-privileged users can upload, extract, sync, or rename files into directories that are listed to other users.
- Disable public directory indexing unless there is a clear business requirement.
- Add server-side filename validation to block basenames beginning with dangerous URI schemes such as javascript:, data:, and vbscript:.
- Search existing file stores and deployment artifacts for file names beginning with javascript: or encoded variants in directories exposed by web listings.
- Review web access logs, upload logs, object storage audit logs, file sync logs, and application events for suspicious filename creation followed by directory listing access.
- Add regression tests that render directory listings containing hostile filenames and assert that generated links cannot execute script.
The record
Rack is a modular Ruby web server interface. Prior to versions 2.2.22, 3.1.20, and 3.2.5, `Rack::Directory` generates an HTML directory index where each file entry is rendered as a clickable link. If a file exists on disk whose basename starts with the `javascript:` scheme (e.g. `javascript:alert(1)`), the generated index contains an anchor whose `href` is exactly `javascript:alert(1)`. Clicking the entry executes JavaScript in the browser (demonstrated with `alert(1)`). Versions 2.2.22, 3.1.20, and 3.2.5 fix the issue.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| RubyGems | rack | 0 | 2.2.22 |
| RubyGems | rack | 3.0.0.beta1 | 3.1.20 |
| RubyGems | rack | 3.2.0 | 3.2.5 |
| Chainguard | gitlab-exporter-18.6 | 0 | 18.6.6-r1 |
| Chainguard | gitlab-exporter-18.7 | 0 | 18.7.4-r1 |
| Chainguard | gitlab-exporter-18.8 | 0 | 18.8.4-r1 |
| Chainguard | gitlab-rails-ce-18.8 | 0 | 18.8.7-r0 |
| Chainguard | gitlab-rails-ce-18.9 | 0 | 18.9.3-r0 |
| Chainguard | gitlab-rails-ce-fips-18.8 | 0 | 18.8.7-r0 |
| Chainguard | gitlab-rails-ce-fips-18.9 | 0 | 18.9.3-r0 |
| Chainguard | kube-fluentd-operator | 0 | 1.18.2-r60 |
| Chainguard | logstash-8.17 | 0 | 8.17.10-r12 |
| Chainguard | logstash-8.17-iamguarded-compat | 0 | 8.17.10-r12 |
| Chainguard | logstash-8.17-with-output-opensearch | 0 | 8.17.10-r12 |
| Chainguard | logstash-8.19 | 0 | 8.19.11-r1 |
| Chainguard | logstash-8.19-iamguarded-compat | 0 | 8.19.11-r1 |
| Chainguard | logstash-8.19-with-output-opensearch | 0 | 8.19.11-r1 |
| Chainguard | logstash-9.0 | 0 | 9.0.8-r11 |
| Chainguard | logstash-9.0-iamguarded-compat | 0 | 9.0.8-r11 |
| Chainguard | logstash-9.0-with-output-opensearch | 0 | 9.0.8-r11 |
| Chainguard | logstash-9.1 | 0 | 9.1.10-r1 |
| Chainguard | logstash-9.1-bitnami-compat | 0 | 9.1.10-r1 |
| Chainguard | logstash-9.1-iamguarded-compat | 0 | 9.1.10-r1 |
| Chainguard | logstash-9.1-with-output-opensearch | 0 | 9.1.10-r1 |
| Chainguard | logstash-9.2 | 0 | 9.2.5-r1 |
| Chainguard | logstash-9.2-iamguarded-compat | 0 | 9.2.5-r1 |
| Chainguard | logstash-9.2-with-output-opensearch | 0 | 9.2.5-r1 |
| Chainguard | logstash-9.3 | 0 | 9.3.1-r1 |
| Chainguard | logstash-9.3-iamguarded-compat | 0 | 9.3.1-r1 |
| Chainguard | logstash-9.3-with-output-opensearch | 0 | 9.3.1-r1 |
| Chainguard | ruby3.2-rails-7.1 | 0 | 7.1.6-r2 |
| Chainguard | ruby3.2-rails-7.2 | 0 | 7.2.3-r2 |
| Chainguard | ruby3.2-rails-8.0 | 0 | 8.0.4-r2 |
| Chainguard | ruby3.2-rails-8.1 | 0 | 8.1.2-r1 |
| Chainguard | ruby3.3-rack-2.2 | 0 | 2.2.22-r0 |
| Chainguard | ruby3.3-rails-7.1 | 0 | 7.1.6-r2 |
| Chainguard | ruby3.3-rails-7.2 | 0 | 7.2.3-r2 |
| Chainguard | ruby3.3-rails-8.0 | 0 | 8.0.4-r2 |
| Chainguard | ruby3.3-rails-8.1 | 0 | 8.1.2-r2 |
| Chainguard | ruby3.4-rails-7.1 | 0 | 7.1.6-r2 |
| Chainguard | ruby3.4-rails-7.2 | 0 | 7.2.3-r2 |
| Chainguard | ruby3.4-rails-8.0 | 0 | 8.0.4-r2 |
| Chainguard | ruby3.4-rails-8.1 | 0 | 8.1.2-r1 |
| Chainguard | ruby4.0-rails-7.1 | 0 | 7.1.6-r1 |
| Chainguard | ruby4.0-rails-7.2 | 0 | 7.2.3-r2 |
| Chainguard | ruby4.0-rails-8.0 | 0 | 8.0.4-r1 |
| Chainguard | ruby4.0-rails-8.1 | 0 | 8.1.2-r1 |
| Wolfi | kube-fluentd-operator | 0 | 1.18.2-r60 |
| Wolfi | logstash-9.1 | 0 | 9.1.10-r1 |
| Wolfi | logstash-9.1-bitnami-compat | 0 | 9.1.10-r1 |
| Wolfi | logstash-9.1-iamguarded-compat | 0 | 9.1.10-r1 |
| Wolfi | logstash-9.1-with-output-opensearch | 0 | 9.1.10-r1 |
| Wolfi | logstash-9.2 | 0 | 9.2.5-r1 |
| Wolfi | logstash-9.2-iamguarded-compat | 0 | 9.2.5-r1 |
| Wolfi | logstash-9.2-with-output-opensearch | 0 | 9.2.5-r1 |
| Wolfi | logstash-9.3 | 0 | 9.3.1-r1 |
| Wolfi | logstash-9.3-iamguarded-compat | 0 | 9.3.1-r1 |
| Wolfi | logstash-9.3-with-output-opensearch | 0 | 9.3.1-r1 |
| Wolfi | ruby3.2-rails-8.0 | 0 | 8.0.4-r2 |
| Wolfi | ruby3.2-rails-8.1 | 0 | 8.1.2-r1 |
| Wolfi | ruby3.3-rack-2.2 | 0 | 2.2.22-r0 |
| Wolfi | ruby3.3-rails-8.0 | 0 | 8.0.4-r2 |
| Wolfi | ruby3.3-rails-8.1 | 0 | 8.1.2-r2 |
| Wolfi | ruby3.4-rails-8.0 | 0 | 8.0.4-r2 |
| Wolfi | ruby3.4-rails-8.1 | 0 | 8.1.2-r1 |
| Wolfi | ruby4.0-rails-8.1 | 0 | 8.1.2-r1 |
| openSUSE:Tumbleweed | rubygem-rack-2.2 | 0 | 2.2.22-1.1 |
Related vulnerabilities
- CVE-2026-22860 Rack is a modular Ruby web server interface. Also affects rack
- CVE-2025-61919 Rack is vulnerable to a memory-exhaustion DoS through unbounded URL-encoded body parsing Also affects rack
- CVE-2025-61780 Rack has a Possible Information Disclosure Vulnerability Also affects rack
- CVE-2025-61770 Rack's unbounded multipart preamble buffering enables DoS (memory exhaustion) Also affects rack
- CVE-2025-61771 Rack: Multipart parser buffers large non‑file fields entirely in memory, enabling DoS… Also affects rack
- CVE-2025-61772 Rack's multipart parser buffers unbounded per-part headers, enabling DoS (memory… Also affects rack
- CVE-2025-59830 Rack has an unsafe default in Rack::QueryParser allows params_limit bypass via… Also affects rack
- CVE-2025-46336 Rack::Session is a session management implementation for Rack. Also affects rack