CVE-2026-54659 Overview
CVE-2026-54659 is a path traversal vulnerability [CWE-22] in Pagy, an agnostic pagination library for Ruby. The flaw affects versions 43.0.0 through 43.5.5. The Pagy::I18n.locale= setter in gem/lib/pagy/modules/i18n/i18n.rb stored locale values verbatim and later concatenated them into <locale>.yml path components. Attackers can supply params[:locale] values containing absolute paths or ../ sequences to probe the filesystem. This creates a file existence and readability oracle for YAML files on the host. The issue is fixed in version 43.5.6.
Critical Impact
Unauthenticated network attackers can determine the presence and readability of arbitrary YAML files by manipulating the locale parameter, enabling reconnaissance of application internals and sensitive configuration paths.
Affected Products
- Pagy gem versions 43.0.0 through 43.5.5
- Ruby applications passing params[:locale] directly to Pagy::I18n.locale=
- Rails applications integrating Pagy without input sanitization
Discovery Timeline
- 2026-07-28 - CVE-2026-54659 published to NVD
- 2026-07-29 - Last updated in NVD database
Technical Details for CVE-2026-54659
Vulnerability Analysis
The vulnerability resides in Pagy::I18n.locale=, which accepted arbitrary strings and used them as filesystem path components when locating YAML translation files. Because the setter performed no validation, an attacker-controlled locale value flows directly into a File.exist?-style check against <locale>.yml. The application's differential response reveals whether a target path exists and is readable by the Ruby process.
This behavior turns a translation loader into an oracle. An attacker can iterate over candidate paths such as /etc/passwd or ../../config/database and observe timing or error variations. The impact is limited to disclosure of file existence and readability, not direct content exfiltration. However, this reconnaissance capability accelerates follow-on attacks against adjacent components.
Root Cause
The root cause is missing input validation on the locale setter. RFC 4647 defines a strict grammar for language tags, but Pagy did not enforce it. Any string, including one containing / or .., was accepted and interpolated into a path.
Attack Vector
An unauthenticated attacker sends an HTTP request with a crafted locale parameter. The application propagates the value into Pagy::I18n.locale=, which then attempts to resolve a YAML file at the attacker-specified path. The server's response, timing, or error state signals whether the path exists.
# Patched code in gem/lib/pagy/modules/i18n/i18n.rb
module I18n
class KeyError < KeyError; end
# Match only valid locale names. (See https://www.rfc-editor.org/info/rfc4647/)
LOCALE_PATTERN = /\A[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*\z/
extend self
def pathnames
Source: GitHub Commit efcf096
The fix introduces LOCALE_PATTERN, a regular expression aligned with RFC 4647 that rejects any input containing path separators or traversal sequences.
Detection Methods for CVE-2026-54659
Indicators of Compromise
- HTTP requests containing locale parameter values with ../, ..\, or absolute path prefixes such as /etc/ or C:\
- Repeated requests iterating through locale values that do not match the RFC 4647 language tag grammar
- Application logs showing Pagy::I18n::KeyError bursts tied to a single client IP
Detection Strategies
- Inspect web server and application logs for locale query parameters or form fields containing non-alphanumeric characters beyond hyphens
- Deploy WAF rules that reject request parameters named locale when values fail to match ^[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*$
- Correlate 4xx/5xx response spikes with locale parameter anomalies to identify oracle probing
Monitoring Recommendations
- Alert on high-volume access to endpoints where Pagy pagination is exposed, filtered by unusual locale values
- Track file system access events from the Ruby process to sensitive paths such as /etc/, /root/, or application config directories
- Baseline normal locale values used by your application and flag deviations for review
How to Mitigate CVE-2026-54659
Immediate Actions Required
- Upgrade the Pagy gem to version 43.5.6 or later using bundle update pagy
- Audit application code for any direct assignment of user input to Pagy::I18n.locale= and add validation
- Review recent access logs for anomalous locale parameter values that may indicate prior probing
Patch Information
The fix ships in Pagy 43.5.6. See the GitHub Security Advisory GHSA-2xmw-f8j8-wfxc and GitHub Release 43.5.6 for release notes. The corresponding change is tracked in Pull Request #908 and commit efcf0969.
Workarounds
- Validate params[:locale] against an allowlist of supported languages before passing it to Pagy
- Enforce the RFC 4647 pattern \A[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*\z at the controller layer
- Restrict Ruby process file permissions so it cannot read sensitive files outside the application root
# Update Pagy in your Gemfile and install the fixed version
bundle update pagy --conservative
bundle exec ruby -e "require 'pagy'; puts Pagy::VERSION"
# Expected output: 43.5.6 or later
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

