Vulnerabilities in pkg:gem/pagy
PACKAGECVE-2026-54659 is a MODERATE pagy i18n locale option is vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting Pagy libraries in the RubyGems ecosystem. The issue involves pagy i18n locale option is not validated before being used in a file path. Remediation is available by upgrading affected packages to version 43.5.6.
pkg:gem/pagy
Vulnerability advisories affecting package pkg:gem/pagy. Select an advisory below to view technical details or fixes.
| Advisory ID | CVE / NVD | Severity | Summary |
|---|---|---|---|
| GHSA-2xmw-f8j8-wfxc | CVE-2026-54659 | MODERATE | Pagy I18n locale option is not validated before being used in a file path |
CVE-2026-54659 at a Glance
How to Fix CVE-2026-54659
To remediate this vulnerability, upgrade all affected Pagy dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade pagy to 43.5.6
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for pagy
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-54659, inspect your project dependencies for Pagy:
inspect dependencies for pagy
Analyze the terminal output to locate any version of Pagy in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 43.5.6), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In Pagy, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-54659 Affected Pagy Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
pagy
|
RubyGems |
≥ 43.0.0
< 43.5.6
|
43.5.6
|
References
Frequently Asked Questions
What is CVE-2026-54659?
Which Pagy versions are affected?
What version fixes CVE-2026-54659?
Is pagy affected?
What CWE is associated with CVE-2026-54659?
How can I check RubyGems dependencies for CVE-2026-54659?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-2xmw-f8j8-wfxc",
"modified" : "2026-07-28T22:25:29Z",
"published" : "2026-07-28T22:25:29Z",
"aliases" : [ "CVE-2026-54659" ],
"summary" : "Pagy I18n locale option is not validated before being used in a file path",
"details" : "### Summary\n\n`Pagy::I18n.locale=` did not validate its argument before using it as a\npath component to load the matching dictionary file (`<locale>.yml`). An\napplication that assigns untrusted input to the locale — e.g. the common\npattern `Pagy::I18n.locale = params[:locale]` — let that input influence\nwhich file Pagy attempted to load.\n\n### Details\n\nThe setter stored the value as-is, and the loader joined it into a path\nand read it:\n\n```ruby\n# gem/lib/pagy/modules/i18n/i18n.rb\ndef locale=(value)\n Thread.current[:pagy_locale] = value.to_s\nend\n\n# ...later, when translating:\npath = pathnames.reverse.map { |p| p.join(\"#{locale}.yml\") }.find(&:exist?)\ndictionary = YAML.load_file(path)[locale]\n```\n\nBecause the locale was used verbatim, a value such as an absolute path or\na `../`-style string redirected the lookup outside the locales directory.\nPagy's subsequent structural check (`dictionary['pagy']['p11n']`)\nprevents the file's contents from being returned, so this is **not** a\ndirect file read.\n\nFixed in 43.5.6 by constraining the locale to a BCP 47 shape before use:\n\n```ruby\nLOCALE_PATTERN = /\\A[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*\\z/\n\ndef locale=(value)\n Thread.current[:pagy_locale] = value.to_s[LOCALE_PATTERN]\nend\n```\n\nAny non-matching value (including `nil`) resolves to the default locale\nand never reaches the file lookup.\n\n### PoC\n\nIn an application that sets `Pagy::I18n.locale = params[:locale]`, the\nloader appends `.yml` and reads `<locale>.yml`, so the request param\ncontrols the target path. For example, pointing it at the app's\n`config/database.yml`:\n\n1. Send a request with `?locale=../../../config/database` (adjust the\n number of `../` to reach the app root from the gem's `locales/`\n directory).\n2. Pagy calls `YAML.load_file` on the resulting `…/config/database.yml`.\n3. The outcome differs by whether that `.yml` exists, is readable, parses\n as YAML, and has Pagy's expected structure — an existing, readable\n `config/database.yml` raises a different error than a non-existent\n path (which silently falls back to the default locale). This yields a\n file-existence / readability oracle for `.yml` paths, and the targeted\n file is read into the process during the attempt.\n\n### Impact\n\nInformation disclosure (CWE-22 / CWE-200): a file-existence / readability\noracle for `.yml` paths on the host, plus a server-side read of\nattacker-chosen files into the process. The file contents are not\nreturned in the response.\n\nOnly applications that pass **unsanitized end-user input** into\n`Pagy::I18n.locale=` are affected. Applications that set the locale from\ntrusted values are not affected.\n\n**Patched:** pagy 43.5.6.\n**Workaround (if you cannot upgrade):** validate the locale before\nassigning it, e.g.\n`Pagy::I18n.locale = params[:locale].to_s[/\\A[a-zA-Z]{2,8}(-[a-zA-Z0-9]{1,8})*\\z/]`,\nor restrict it to your known set of locales.",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "RubyGems",
"name" : "pagy"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "43.0.0"
}, {
"fixed" : "43.5.6"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/ddnexus/pagy/security/advisories/GHSA-2xmw-f8j8-wfxc"
}, {
"type" : "WEB",
"url" : "https://github.com/ddnexus/pagy/pull/908"
}, {
"type" : "WEB",
"url" : "https://github.com/ddnexus/pagy/commit/efcf09690e9fa7d7abdfb987b785a55f87e287df"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/ddnexus/pagy"
}, {
"type" : "WEB",
"url" : "https://github.com/ddnexus/pagy/releases/tag/43.5.6"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-200", "CWE-22" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-28T22:25:29Z",
"nvd_published_at" : null
}
}