CVE-2026-40295: Devise Devise Has An Open Redirect Vulnerability

MODERATE
Advisory Identifier: GHSA-jp94-3292-c3xv
CVSS 6.1
CWE-601
Published
Advisory Summary

CVE-2026-40295 is a MODERATE (CVSS 6.1) devise has an open redirect vulnerability (CWE-601: URL Redirection to Untrusted Site ('Open Redirect')) affecting Devise libraries in the RubyGems ecosystem. The issue involves devise has an open redirect via unvalidated `request.referrer` in timeoutable session timeout handler. Remediation is available by upgrading affected packages to version 5.0.4.

CVE-2026-40295 at a Glance

CVE Identifier CVE-2026-40295
GHSA Identifier GHSA-jp94-3292-c3xv
Severity MODERATE
CVSS v3.1 Base Score 6.1
CWE Classification CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
Affected Product Devise
Package Ecosystem RubyGems
Published Date
Last Updated

Security Impact

CVSS: 6.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-40295

To remediate this vulnerability, upgrade all affected Devise dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

devise fixed: 5.0.4
Upgrade devise to 5.0.4
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for devise

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-40295, inspect your project dependencies for Devise:

inspect dependencies for devise

Analyze the terminal output to locate any version of Devise in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.0.4), 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-601: URL Redirection to Untrusted Site ('Open Redirect'), where the web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect. In Devise, 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

## Summary When the `Timeoutable` module is enabled in Devise, the `FailureApp#redirect_url` method returns `request.referrer` — the HTTP `Referer` header, which is attacker-controllable — without validation for any non-GET request that results in a session timeout. An attacker who hosts a page with an auto-submitting cross-origin form can cause a victim with an expired Devise session to be redirected to an arbitrary external URL. This contrasts with the GET timeout path (which uses server-side `attempted_path`) and Devise's own `store_location_for` mechanism (which strips external hosts via `extract_path_from_location`), both of which are protected; only the non-GET timeout redirect path is unprotected. ## Details The vulnerable code is in `lib/devise/failure_app.rb`: ```ruby def redirect_url if warden_message == :timeout flash[:timedout] = true if is_flashing_format? path = if request.get? attempted_path # safe: server-side value from warden options else request.referrer # UNSAFE: HTTP Referer header, attacker-controlled end path || scope_url else scope_url end end ``` This is passed directly to `redirect_to`: ```ruby def redirect store_location! # ... redirect_to redirect_url # redirect_url may be an external attacker URL end ``` The GET timeout path uses `attempted_path`, which is set server-side by Warden and cannot be influenced by the client. The `store_location!` method also only runs for GET requests, so no session-based protection is applied on POST timeouts. By contrast, Devise's `store_location_for` method (used elsewhere) correctly sanitizes URLs via `extract_path_from_location`, which strips the scheme and host. ## Impact - Victims with expired sessions who click any attacker-crafted link or visit an attacker page with an auto-submitting form are redirected to an arbitrary external URL. - The redirect happens transparently via a trusted domain (the target app's domain), bypassing browser phishing warnings. - An attacker can redirect victims to a fake login page to harvest credentials (phishing), or to malicious download sites. _Note_: Rails' built-in open-redirect protection does not mitigate this issue. `Devise::FailureApp` is an `ActionController::Metal` app with its own isolated copy of the relevant redirect configuration, so `config.action_controller.action_on_open_redirect = :raise` (and the older `raise_on_open_redirects` setting) do not reach it. ## Patches This is patched in Devise v5.0.4. Users should upgrade as soon as possible. ## Workaround None beyond upgrading. If an upgrade is not immediately possible, the same changes from the patch commit can be applied as a monkey-patch in a Rails initializer (`Devise::FailureApp#redirect_url` and `Devise::Controllers::StoreLocation#extract_path_from_location`). Remove the monkey-patch after upgrading.

CVE-2026-40295 Affected Devise Versions

1 component(s)
Fixed Versions:
5.0.4
Product / Package Ecosystem Affected Versions Fixed Version
devise
RubyGems
< 5.0.4
5.0.4

References

Frequently Asked Questions

What is CVE-2026-40295?
CVE-2026-40295 is a security vulnerability in Devise involving Devise has an Open Redirect via Unvalidated `request.referrer` in Timeoutable Session Timeout Handler under CWE-601: URL Redirection to Untrusted Site ('Open Redirect').
Which Devise versions are affected?
Affected versions include releases prior to 5.0.4 across affected packages: devise.
What version fixes CVE-2026-40295?
Upgrading to 5.0.4 (or the latest patched release for your respective branch) resolves the vulnerability.
Is devise affected?
Yes, devise is affected in releases prior to 5.0.4. Upgrade your dependency to 5.0.4 or later.
What is the CVSS score of CVE-2026-40295?
CVE-2026-40295 has a CVSS v3.1 base score of 6.1 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N.
What CWE is associated with CVE-2026-40295?
CVE-2026-40295 is classified under CWE-601: URL Redirection to Untrusted Site ('Open Redirect') (The web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect.).
How can I check RubyGems dependencies for CVE-2026-40295?
Run the dependency tree command: 'inspect dependencies for devise'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-jp94-3292-c3xv",
  "modified" : "2026-05-29T21:44:44Z",
  "published" : "2026-05-08T15:41:47Z",
  "aliases" : [ "CVE-2026-40295" ],
  "summary" : "Devise has an Open Redirect via Unvalidated `request.referrer` in Timeoutable Session Timeout Handler",
  "details" : "## Summary\n\nWhen the `Timeoutable` module is enabled in Devise, the `FailureApp#redirect_url` method returns `request.referrer` — the HTTP `Referer` header, which is attacker-controllable — without validation for any non-GET request that results in a session timeout. An attacker who hosts a page with an auto-submitting cross-origin form can cause a victim with an expired Devise session to be redirected to an arbitrary external URL. This contrasts with the GET timeout path (which uses server-side `attempted_path`) and Devise's own `store_location_for` mechanism (which strips external hosts via `extract_path_from_location`), both of which are protected; only the non-GET timeout redirect path is unprotected.\n\n## Details\n\nThe vulnerable code is in `lib/devise/failure_app.rb`:\n\n```ruby\ndef redirect_url\n  if warden_message == :timeout\n    flash[:timedout] = true if is_flashing_format?\n\n    path = if request.get?\n      attempted_path          # safe: server-side value from warden options\n    else\n      request.referrer        # UNSAFE: HTTP Referer header, attacker-controlled\n    end\n\n    path || scope_url\n  else\n    scope_url\n  end\nend\n```\n\nThis is passed directly to `redirect_to`:\n\n```ruby\ndef redirect\n  store_location!\n  # ...\n  redirect_to redirect_url   # redirect_url may be an external attacker URL\nend\n```\n\nThe GET timeout path uses `attempted_path`, which is set server-side by Warden and cannot be influenced by the client. The `store_location!` method also only runs for GET requests, so no session-based protection is applied on POST timeouts.\n\nBy contrast, Devise's `store_location_for` method (used elsewhere) correctly sanitizes URLs via `extract_path_from_location`, which strips the scheme and host.\n\n## Impact\n\n- Victims with expired sessions who click any attacker-crafted link or visit an attacker page with an auto-submitting form are redirected to an arbitrary external URL.\n- The redirect happens transparently via a trusted domain (the target app's domain), bypassing browser phishing warnings.\n- An attacker can redirect victims to a fake login page to harvest credentials (phishing), or to malicious download sites.\n\n_Note_: Rails' built-in open-redirect protection does not mitigate this issue. `Devise::FailureApp` is an `ActionController::Metal` app with its own isolated copy of the relevant redirect configuration, so `config.action_controller.action_on_open_redirect = :raise` (and the older `raise_on_open_redirects` setting) do not reach it.\n\n## Patches\n\nThis is patched in Devise v5.0.4. Users should upgrade as soon as possible.\n\n## Workaround\n\nNone beyond upgrading. If an upgrade is not immediately possible, the same changes from the patch commit can be applied as a monkey-patch in a Rails initializer (`Devise::FailureApp#redirect_url` and `Devise::Controllers::StoreLocation#extract_path_from_location`). Remove the monkey-patch after upgrading.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "RubyGems",
      "name" : "devise"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.0.4"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 5.0.3"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/heartcombo/devise/security/advisories/GHSA-jp94-3292-c3xv"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-40295"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/heartcombo/devise/commit/025fe2124f9928766fc46520e999633b598d0360"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/heartcombo/devise"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/devise/CVE-2026-40295.yml"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-601" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-08T15:41:47Z",
    "nvd_published_at" : "2026-05-22T20:16:34Z"
  }
}